GNU C和ANSI C
GNU C和ANSI 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 C和ISO表示发布的组织,由最开始的美国国家标准,最后变成国际标准。
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];
比如,图像处理时,
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号