Почему размер упакованной структуры будет отличаться в Linux и Windows при использовании gcc?

#c #c #gcc #mingw #sizeof

#c #c #gcc #mingw #sizeof

Вопрос:

В приведенном ниже коде объясняется, почему размер упакованной структуры отличается в Linux и Windows при компиляции с помощью gcc?

 #include <inttypes.h>
#include <cstdio>

// id3 header from an mp3 file
struct header
{    
        uint8_t version[ 2 ];
        uint8_t flags;
        uint32_t size;
} __attribute__((packed));

int main( int argc, char **argv )
{
        printf( "%un", (unsigned int)sizeof( header ) );
        return 0;
}
  

используемые версии gcc:

 $ g   --version
g   (Ubuntu/Linaro 4.5.2-8ubuntu4) 4.5.2
$ x86_64-w64-mingw32-g   --version
x86_64-w64-mingw32-g   (GCC) 4.7.0 20110831 (experimental)
  

Скомпилируйте и протестируйте:

 $ g   -Wall packed.cpp -o packed amp;amp; ./packed
7
$ x86_64-w64-mingw32-g   -Wall packed.cpp -o packed.exe
--> prints '8' when run on Windows.
  

Двоичный файл Linux выводит ожидаемый размер 7 байт, двоичный файл Windows — 8 байт. В чем разница?

Комментарии:

1. Я предполагаю, что атрибут каким-то образом игнорируется (из-за ошибки). Используйте offsetof(header, size) , чтобы выяснить, так ли это.

2. Если я скомпилирую его непосредственно из Windows xp с помощью MinGW g 4.5.2, он печатает 7. 32 бит.

3. ожидается изменение размеров структуры, поэтому рекомендуется никогда не использовать / передавать структуры в доменах компиляции.

4. Примечание: любой код на C или C , который зависит от выравнивания элементов определенной структуры (например, чтение или запись структур непосредственно на диск или в сеть), плохо пахнет…

5. Meh, это только звучит плохо.

Ответ №1:

gcc 4.7.0 это позволяет быть совместимым с 64-разрядным MSVC . Если вы хотите правильно упаковать структуру, скомпилируйте с -mno-ms-bitfields помощью . (Но тогда ваш макет будет несовместим с MSVC .)

Ответ №2:

Раздел 6.37.3 атрибутов gcc объясняет это как разницу в спецификациях ABI, смотрите Здесь: http://gcc.gnu.org/onlinedocs/gcc/Type-Attributes.html

Комментарии:

1. Компилятор Microsoft позволяет упаковывать элементы так плотно, как вам нравится. См.: #pragma pack для компилятора MS.

Ответ №3:

Атрибут((packed)) зависит от компилятора для GCC. Следовательно, этот код даже не будет компилироваться с MSVC . Возможно, вы использовали другой компилятор для Windows. Однако с MSVC вы могли бы это сделать:

 #include <stdint.h>
#include <cstdio>

// id3 header from an mp3 file
#pragma pack(push,1)
struct header
{    
        uint8_t version[ 2 ];
        uint8_t flags;
        uint32_t size;
};
#pragma pack(pop)

int main( int argc, char **argv )
{
        printf( "%un", (unsigned int)sizeof( header ) );
        return 0;
}
  

и структура будет составлять 7 байт.

Комментарии:

1. Но он будет отлично компилироваться с использованием mingw под Windows, который, как представляется, использует OP

Ответ №4:

Это все о выравнивании атрибутов и слов в памяти

посмотрите, пишете ли вы

 struct header
{    
        uint8_t version[ 2 ];
        uint8_t flags;
        uint32_t size;
};
  

тогда linux и Windows имеют размер 8

но когда вы указываете атрибут, чтобы избежать выравнивания мира по умолчанию, тогда

 struct header
{    
        uint8_t version[ 2 ];
        uint8_t flags;
        uint32_t size;
} __attribute__((packed));
  

затем в Linux из-за размера attritube становится 7

см. Спецификацию gcc, в которой говорится, что

 If packed is used on a structure, or if bit-fields are used 
it may be that the Microsoft ABI packs them differently than 
GCC would normally pack them. 
  

Комментарии:

1. Возможно, потому compiler specific , что бит не имеет значения? Важна цитата об ABI.

2. я добавил, что пользователь bcz собирается скомпилировать программу с атрибутом ((packed)) в Windows, атрибут ((packed)) не поддерживается в компиляторе Windows

3. «компилятор Windows»? OP указывает, что он использует GCC как в Linux, так и в Windows — MSVC не единственный компилятор для Windows.

Ответ №5:

Обновить. Последняя версия MinGW работает нормально.

Оба g (i686-win32-dwarf-rev0, Built by MinGW-W64 project) 8.1.0 и g (x86_64-win32-seh-rev0, Built by MinGW-W64 project) 8.1.0 выводит sizeof() примера кода в точности равен 7 байтам.