GNU C和ANSI C

GNU CANSI C的概念

ANSI C指的是American National Standards Institute(美国国家标准协会)C。这个标准的演进过程如下:

1989 - ANSI C (C89/C90)
  ↓
1999 - ISO C (C99)
  ↓  
2011 - ISO C (C11)
  ↓
2017 - ISO C (C17)

Cxx表示标准的版本号,实际就是发布的年份。前面的ANSI CISO表示发布的组织,由最开始的美国国家标准,最后变成国际标准。

GNU C表示在标准C规范上的扩展,扩展通常引入一些额外的语法,不同的编译器可能实现了不同的扩展,导致程序的移植性变差,但是如果代码遵循ANSI C规范,就基本可以保证移植性,因为基本上C编译器都完整实现了ANSI C规范。除了有GNU C扩展,还存在其他较流行的一些扩展:

扩展类型 示例 编译器支持
GNU C typeof(), ({ }), attribute GCC, Clang
MSVC __asm, __stdcall MSVC
嵌入式 data, code, xdata Keil, IAR

GNU C扩展

这里只介绍这个,因为其他两个工作中接触不到,所以不太了解。如果仅仅想使用ANSI C标准,禁用扩展,只需要编译时带上-std=cxx --pedantic参数(gcc版本9.5.0,低版本可能是其他参数)。它表示按照cxx版本的标准C检查,如果不指定-std=cxx可能不起作用。

零长度和变量长度数组

零长度数组

零长度数组最常见于结构体中的数组成员:

struct A
{
    int cmd;
    int count;
    char data[0];
};

这个扩展的一个经典用法是做内存数据反序列化时,例如自定义通讯协议时,假定通信协议数据结构是:命令+数据长度+数据。而数据长度会随着命令的不同而变化,如果不支持0长度数组,那就不能定义一个结构体来描述它,有了这个扩展,只需要一个强制类型转换,就可以轻松反序列化协议数据了。

不过现在的ANSI C通过柔性数组实现了一样的功能:

struct A
{
    int cmd;
    int count;
    char data[]; //定义数组时,不写数组长度
};

在此之前,要定义结构体描述这个协议,可能会想到使用指针:

struct A
{
    int cmd;
    int count;
    char *data;
};

虽然可以描述该通讯协议,但是无法直接直接强制类型转换实现反序列化,解析后的数据也破坏了原来内存的连续性。

💡 需要注意0长度数组和柔性数组都不占用内存空间,即sizeof(struct A) == 8

变量长度数组

int size = 5;
char buffer[size];

比如,图像处理时,

posted @ 2025-10-28 16:22  thammer  阅读(5)  评论(0)    收藏  举报