ПроблемаСравнение данных заполнения в память происходит, когда вы используете memcmp
функция для сравнения двух структур в целом. В процессе сравниваются бессмысленные данные, хранимые в заполнении структуры.
Для образца:
struct structType {
char member1;
int member2;
//...
//...
};
structType var1;
structType var2;
//...
//...
if(memcmp(&var1,&var2,sizeof(var1)))
{...}
РискЕсли представители структуры имеют различные типы данных, ваш компилятор вводит дополнительное заполнение для выравнивания данных в памяти. Пример заполнения см. в разделе Higher Estimate of Local Variable Size
.
Содержимое этих дополнительных байтов заполнения бессмысленно. Стандарт C позволяет содержимое этих байтов быть неопределенным, предоставляя различным компиляторам широту для реализации собственного заполнения. Если вы выполняете байтовое сравнение структур с memcmp
, вы сравниваете даже бессмысленные данные, хранящиеся в заполнении. Вы можете прийти к ложному выводу, что две структуры данных не равны, даже если их соответствующие представители имеют одинаковое значение.
ЗафиксироватьВместо сравнения двух структур в одной попытке сравните представителя структур по представителям.
Для эффективного кода запишите функцию, которая делает представитель сравнения по представителям. Используйте эту функцию для сравнения двух структур.
Можно использовать memcmp
для байтового сравнения структур только в том случае, если известно, что структуры не содержат заполнения. Обычно, чтобы предотвратить заполнение, вы используете определенные атрибуты или прагмы, такие как #pragma pack
. Однако эти атрибуты или прагмы не поддерживаются всеми компиляторами и делают вашу реализацию кода зависимой. Если ваши структуры содержат битовые поля, использование этих атрибутов или прагм не может предотвратить заполнение.
Пример - Структуры по сравнению с memcmp
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define fatal_error() abort()
typedef struct s_padding
{
char c;
int i;
unsigned int bf1:1;
unsigned int bf2:2;
unsigned char buffer[20];
} S_Padding ;
/* Function that guarantees safe access to the input memory */
extern int trusted_memory_zone(void *ptr, size_t sz);
int func(const S_Padding *left, const S_Padding *right)
{
if (!trusted_memory_zone((void *)left, sizeof(S_Padding)) ||
!trusted_memory_zone((void *)right, sizeof(S_Padding))) {
fatal_error();
}
if (0 == memcmp(left, right, sizeof(S_Padding)))
{
return 1;
}
else
return 0;
}
В этом примере memcmp
сравнивает байт за байтом две структуры, которые left
и right
указать на. Даже если значения, сохраненные в представителях структуры, одинаковы, сравнение может показать неравенство, если бессмысленные значения в байтах заполнения не совпадают.
Коррекция - Сравнение представителей структур по представителямОдной из возможных коррекций является сравнение отдельных представителей структуры.
Примечание
Можно сравнить целые массивы при помощи memcmp
. Все представители массива имеют совпадающий тип данных. Заполнение байтов не требуется для хранения массивов.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define fatal_error() abort()
typedef struct s_padding
{
char c;
int i;
unsigned int bf1:1;
unsigned int bf2:2;
unsigned char buffer[20];
} S_Padding ;
/* Function that guarantees safe access to the input memory */
extern int trusted_memory_zone(void *ptr, size_t sz);
int func(const S_Padding *left, const S_Padding *right)
{
if (!trusted_memory_zone((void *)left, sizeof(S_Padding)) ||
!trusted_memory_zone((void *)right, sizeof(S_Padding))) {
fatal_error();
}
return ((left->c == right->c) &&
(left->i == right->i) &&
(left->bf1 == right->bf1) &&
(left->bf2 == right->bf2) &&
(memcmp(left->buffer, right->buffer, 20) == 0));
}