November 2019

S M T W T F S
      12
34 5 678 9
10111213141516
17181920212223
24252627282930

Style Credit

Expand Cut Tags

No cut tags
Sunday, January 30th, 2005 10:48 pm


Я привык, что структуры можно сравнивать с помощью 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()?
Sunday, January 30th, 2005 09:17 pm (UTC)
Это да, но вопрос немножко не в этом. Получается, что две переменные, одинаковым образом полностю набитые одинаковыми данными, не проходят сравнение посредством memcmp. А посредством == они в C не сравниваются.
Sunday, January 30th, 2005 09:23 pm (UTC)
ну да, это нормально.

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.
Monday, January 31st, 2005 06:37 am (UTC)
Вот этого я и боялся :(
"For more predictable results, perform an explicit component-wise comparison."
Спасибо.