龙空技术网

C与C++利用pragma pack对结构体做成员打包对齐设置

陳小萌zennychen 390

前言:

当前你们对“c语言pragma pack”都比较注重,兄弟们都需要知道一些“c语言pragma pack”的相关知识。那么小编也在网摘上网罗了一些有关“c语言pragma pack””的相关资讯,希望我们能喜欢,我们快快来学习一下吧!

现代主流C和C++编译器MSVC与GCC均支持使用 #pragma pack 来指定某组结构体或联合体(C++还可支持类)的每一个成员的最大对齐字节数。这在某些诸如可跨平台的对象序列化等应用场合会比较有用。下面笔者将介绍GCC与MSVC均能支持的 #pragma pack 的几种形式。

#pragma pack( push [ , n ] ):表示先将当前pack对齐的设置保存在当前编译器栈上,然后用 n 来设置新的pack对齐要求。n是可缺省的。如果缺省,那么以当前编译器默认设置的pack对齐方式进行设置。#pragma pack( pop ):表示将当前pack对齐的设置推出编译器对pack对齐设置的栈,而回到前一个设置。#pragma pack( [ n ] ):表示用 n 来设置新的pack对齐设置。n是可缺省的。如果缺省,那么以当前编译器默认设置的pack对齐方式进行设置。

下面提供一些示例代码为大家提供一个更好的直观感受。以下代码可在Visual Studio 2019或更高版本上的MSVC(通过将C语言编译选项设置为C11或C17)以及GCC 4.8以上、Clang 3.6以上通过编译和运行。

#include <stdio.h>#include <stdalign.h>#pragma pack(2)typedef struct S1{    char c;    int i;} S1;#pragma pack(push, 1)typedef struct S2{    char c;    int i;} S2;typedef struct S3{    char c;    long long ll;} S3;// 恢复为之前pack设置#pragma pack(pop)typedef struct S4{    char c;    long long ll;} S4;// 恢复为当前编译器默认的pack设置#pragma pack()typedef struct S5{    char c;    int i;} S5;int main(void){    // 输出:S1 size: 6, alignment: 2, c offset: 0, i offset: 2    printf("S1 size: %zu, alignment: %zu, c offset: %zu, i offset: %zu\n",        sizeof(S1), alignof(S1), offsetof(S1, c), offsetof(S1, i));    // 输出:S2 size: 5, alignment: 1, c offset: 0, i offset: 1    printf("S2 size: %zu, alignment: %zu, c offset: %zu, i offset: %zu\n",        sizeof(S2), alignof(S2), offsetof(S2, c), offsetof(S2, i));    // 输出:S3 size: 9, alignment: 1, c offset: 0, i offset: 1    printf("S3 size: %zu, alignment: %zu, c offset: %zu, i offset: %zu\n",        sizeof(S3), alignof(S3), offsetof(S3, c), offsetof(S3, ll));    // 输出:S4 size: 10, alignment: 2, c offset: 0, i offset: 2    printf("S4 size: %zu, alignment: %zu, c offset: %zu, i offset: %zu\n",        sizeof(S4), alignof(S4), offsetof(S4, c), offsetof(S4, ll));    // 输出:S5 size: 8, alignment: 4, c offset: 0, i offset: 4    printf("S5 size: %zu, alignment: %zu, c offset: %zu, i offset: %zu\n",        sizeof(S5), alignof(S5), offsetof(S5, c), offsetof(S5, i));}

此外,为了能更方便地为单个结构体等复合类型设置每个成员最大只能以1个字节对齐的设置,GCC和Clang分别提供了扩展语法进行设置。

以下为GCC的语法扩展:

struct __attribute__((packed)) S{    char c;    int i;};

以下为Clang编译器所支持的语法扩展:

struct [[gnu::packed]] S{    char c;    int i;};

请注意,Clang的该语法扩展只能用于C++11开始起的C++编译器以及可支持C2X标准的C语言编译器。印象中,Clang 9开始应该能支持 -std=gnu2x 这一编译选项。因此如果各位在Clang上用的是C编译器的话,需要显式使用该选项。

标签: #c语言pragma pack