Я привык, что структуры можно сравнивать с помощью memcmp(). Сегодня нарвался на неприятность.
Вот кусок программы (без проверок кодов возврата, чтоб понятнее было):
struct termios ios, ios2;
tcgetattr(scfd, &ios);
// тут меняем флажочки в ios
tcsetattr(scfd, TCSANOW, &ios);
// (1)
tcgetattr(scfd, &ios2);
if( memcmp(&ios, &ios2, sizeof(ios)) != 0) {
fprintf(stderr,"Warning: not all parameters successfully set by tcsetattr()\n");
}Стабильно получаю это сообщение об ошибке.
Печатаю все элементы ios и ios2 поштучно - всё нормально, совпадают.
После десяти минут поисков ошибки в программе и в своей ДНК, начинаю печатать уже побайтно.
Обнаруживаю стабильное несовпадение в 49-51 байтах. Ага, это всё от выравнивания по границе слова.
Попробовал в точку (1) добавить ios2=ios1. Помогло.
Структура выглядит так:
typedef unsigned char cc_t;
typedef unsigned int speed_t;
typedef unsigned int tcflag_t;
#define NCCS 32
struct termios
{
tcflag_t c_iflag; /* input mode flags */
tcflag_t c_oflag; /* output mode flags */
tcflag_t c_cflag; /* control mode flags */
tcflag_t c_lflag; /* local mode flags */
cc_t c_line; /* line discipline */
cc_t c_cc[NCCS]; /* control characters */
speed_t c_ispeed; /* input speed */
speed_t c_ospeed; /* output speed */
};Несовпадающие байты - это вовсе даже не в конце, а в середине. После c_cc (начинается со смещения 17 и заканчивается на 48) и перед c_ispeed (смещение 52).
На данной конкретной архитектуре i386 структура копируется не поэлементно, а с помощью rep movsl, но это implmentation dependent. На PowerPC в этом месте вызывается memcpy(&ios2,&ios,60). А вообще говоря, никто этого не обещал.
Так что же, структуры таки надо всегда сравнивать поэлементно, или стандарт предусматривает при копировании структур и копирование всех байтов в пределах sizeof()?
Tags:
no subject
no subject
no subject
no subject
cld movl $15, %ecx leal -152(%ebp), %edi leal -88(%ebp), %esi rep movslP.S. Если там вместо присваивания написать memcpy и включить -O, то получается ровно то же самое :) А если -O не писать, тогда честно вызывается memcpy.
no subject
no subject
Там в труктуры ты бы перекрыл интерфейс IComparable и она бы сравнивалась так, как реализовано в твоём методе.
А вот такое байт вообще лучше забыть, если оперируешь с абстракциями.
А в C++ приходится помнить и что такое стэк, и что такое регистр, и даже что такое деструктор.
no subject
no subject
Но и без мака у C++ ещё много применений пока.
Я к тому что используя C++ нужно быть готовым к машинным ньюансам.
no subject
Изначально речь шла о C, а не о C++.
no subject
есть, конечно, #pragma pack, но чистить память перед использованием полезно всё равно.
no subject
no subject
You should also be careful about using memcmp to compare objects that can contain "holes", such as the padding inserted into structure objects to enforce alignment requirements, extra space at the end of unions, and extra characters at the ends of strings whose length is less than their allocated size. The contents of these "holes" are indeterminate and may cause strange behavior when performing byte-wise comparisons. For more predictable results, perform an explicit component-wise comparison.
no subject
"For more predictable results, perform an explicit component-wise comparison."
Спасибо.