2016-06-17 3 views
1

Это может показаться очень простой вопрос, но я следующие структуры в C++:тетсра структура переменных

struct SMessage 
{ 
    unsigned int id; 
    unsigned int payloadSize; 
    unsigned char data[100]; 
    unsigned char *data2; 
}; 

позволяет сказать, у меня есть две переменных типа SMessage (msg1, msg2) и я хочу тетср отдельных членов msg1 в msg2 (просьба не спрашивать почему!). Я понимаю, что копирование идентификатор и payLoadSize относительно прямой:

memcpy(&msg2.id, &msg1.id, sizeof(unsigned int)); 
memcpy(&msg2.payLoadSize, &msg2.payLoadSize, sizeof(unsigned int)); 

но для копирования данных [] мы должны сделать:

memcpy(&msg2.data, &msg1.data, 100*sizeof(unsigned char)); 

или

memcpy(msg2.data, msg2.data, 100*sizeof(unsigned int)) 

также будет работать, так как данные является объектом массива?

Как мы будем копировать данные элемента структуры2, который вместо этого объявлен как указатель?

+1

напоминание: 'memcpy' будет копировать * указатель *' data2' ** не ** данные, что 'data2' указывает на. –

+3

Почему вы просто не используете 'sizeof msg2.data' для определения размера? Тем не менее, 'msg2 = msg1' также будет работать, чтобы скопировать структуру. Кроме того, использование 'memcpy()' для копирования чего-либо в большинстве случаев является неправильным, поэтому не используйте его вообще! Например. для массивов фиксированного размера вы должны использовать C++ 'std :: array', который позволяет выполнять простые назначения. Даже без этого использование 'std :: copy' было бы намного чище и безопаснее. –

+0

Я согласен с использованием 'std :: copy'. Вероятно, он использует 'memcpy' внутри вашей реализации, и абстракция поможет вам предотвратить ошибки. – KABoissonneault

ответ

2

Любая версия будет работать. Используя амперсанд (&), оператор явно принимает адрес массива, в то время как опускание амперсанда заставляет его неявно брать адрес массива. В итоге результат тот же.

Что еще более важно, это проще и менее подвержены ошибкам использовать SizeOf непосредственно на поле:

std::memcpy(msg2.data, msg1.data, sizeof(msg1.data)); 

Это позволяет избежать опечаток и, что более важно, если изменения размера поля вы не должны идти через ваши места поиска кода, которые вы использовали.

Что касается data2, то zwol в его ответе ниже правилен тем, что он зависит от того, что именно хранит данные2, или, точнее, кто «владеет» данными2 и как будет освобождена переменная. Возможно, вам захочется заглянуть в «мелкое» и «глубокое» копирование.

+0

жаль, что это была ошибка. Я исправил это. – Paindoo

0

Тип выражения msg.data отличается от типа выражения &msg.data, но значения идентичны. Поскольку это C++, поведение очень четко указано в : вызов memcpy вызывает неявное преобразование обоих аргументов указателя в [const] void *, а результат этого преобразования «указывает на начало места хранения, в котором находится объект, как если это наиболее производный объект (а не подобъект базового класса) ". (В C эффект один и тот же, но стандартное менее понятно из-за того, что вы так говорите - вы должны вместе прочитать параграфы 1 и 7 раздела C99 6.3.2.3 и понимать, что memcpy ведет себя «как бы», он преобразует свои аргументы в указатели- к характеру-типа внутренне.)

data объявлен как

unsigned char data[100]; 

поэтому все следующие условия эквивалентны и правильно. Первый из них был бы предпочтительным стилем в большинстве кодовых баз, над которыми я работал.

memcpy(msg2.data, msg1.data, sizeof msg1.data); 

memcpy(msg2.data, msg1.data, 100); 
memcpy(msg2.data, msg1.data, 100 * sizeof(unsigned char)); 

memcpy(&msg2.data, &msg1.data, sizeof msg1.data); 
memcpy(&msg2.data, &msg1.data, 100); 
memcpy(&msg2.data, &msg1.data, 100 * sizeof(unsigned char)); 

Однако

memcpy(msg2.data, msg1.data, 100 * sizeof(unsigned int)); 

НЕПРАВИЛЬНО; он копирует слишком много памяти.¹ Вот почему форма с sizeof является предпочтительным стилем; сложнее ошибиться в первом месте и не станет ошибочным, если изменение типа изменилось. ²

Также в качестве стиля я предпочитаю не писать & в этом контексте, потому что &[anything with an array type] почти всегда неправильно, поэтому его не следует писать таким образом, если это действительно не необходимо.

И вы должны знать, что sizeof(any sort of char) == 1по определению (C++ [expr.sizeof]/1). Мое личное, но широко распространенное мнение, что это означает, что sizeof(char) никогда не должно появляться в вашем коде.

И наконец, я не могу сказать вам правильный способ скопировать data2 без дополнительной информации. Мне нужно знать, что указывает data2, как оно распределено, и следует ли его копировать или ссылаться.


¹ за исключением очень маловероятном случае, sizeof(unsigned char) == sizeof(unsigned int); это было верно в оригинальном Cray, и стандарты по-прежнему допускают возможность, но AFAIK ни один разработчик на самом деле не сделал этого за многие годы.

² Контраргумент: применяется sizeof к типу массива, что является рискованным, потому что типы массивов «распадаются» на типы указателей, если им предоставлена ​​малейшая возможность сделать это, поэтому снова было бы неправильно неправильно. В случае, если вы находитесь, хотя - копирование элементов структуры вручную - я думаю, что это менее опасно, чем альтернатива.

+1

Вам не нужно указывать указатель на void *; вам нужно бросить, чтобы преобразовать из void *. – Steven

+0

@Steven Моя память о стандарте говорит, что вы ошибаетесь в этом, но у меня его нет на этом компьютере, поэтому я не могу проверить. – zwol

+0

Похоже, что это раздел 4.10.2, по крайней мере, текущего рабочего проекта на http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3485.pdf: значение типа «Указатель на cv T», где T - тип объекта, может быть преобразован в prvalue типа «указатель в cv void». – Steven

0

Ваши последние две цифры memcpy() s должны быть sizeof(msg1.data) не 100*sizeof(unsigned int) - их unsigned char s в любом случае!

Но последнее:

memcpy(msg2.data, msg2.data, 100*sizeof(unsigned int)); 

правильно. Если вы хотите использовать ранее один, использование:

memcpy(&msg2.data[0], &msg1.data[0], 100*sizeof(unsigned int)); 
0

Оба они не правы, потому что они будут вызывать вне диапазона доступа, если sizeof(unsigned int) больше sizeof(char).

Вы можете сделать что-либо один из

memcpy(&msg2.data, &msg1.data, sizeof(msg1.data)); // pass pointers to arrays 
memcpy(msg2.data, msg1.data, 100*sizeof(unsigned char)); // pass pointers to first elements of the arrays 
Смежные вопросы