打印
[开发工具]

GCC对C语言的几个扩展

[复制链接]
592|8
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
本帖最后由 zhanzr21 于 2020-7-19 18:11 编辑

不管是True Studio, SW4STM32, 还是最新官方出的STM32CubeIDE, 内置编译工具链默认都是arm-none-eabi-gcc. GCC对C语言的标准支持一般是编译器中比较齐全和迅速的, 除此之外GCC还有一些对ISO C标准的若干扩展. 如果暂时不考虑可移植性的话, 可以合理利用这些扩展. 当然是否利用这些扩展是程序员自己决定, 这里简单介绍几个扩展特性, 以供参考.

内嵌函数

即在函数内部定义函数
int main(void)
{
        /* USER CODE BEGIN 1 */
        void nested_func(void) {
                printf("Inside a nested function!\n");
                printf("%s\n", __VERSION__);
        }
....

        printf("Test nested function\n");
        nested_func();
        printf("\n");
.....
参考输出:
Test nested function
Inside a nested function!
7.3.1 20180622 (release) [ARM/embedded-7-branch revision 261907]






使用特权

评论回复
沙发
zhanzr21|  楼主 | 2020-7-19 18:10 | 只看该作者
0长度数组

用于在结构体中保留后续扩展空间.

struct msg_header {
        uint32_t type;
        uint32_t size;
        uint8_t content[0];
};


        printf("Test zero length of array\n");
        {
                struct msg_header *msg;
                int size = 128;

                msg = (struct msg_header *) malloc(sizeof (struct msg_header) + size);

                msg->type = 0x01;
                msg->size = size;

                printf("msg header  is at %p\n", (void *)msg);
                printf("msg content is at %p\n", (void *)msg->content);
                free(msg);
        }
        printf("\n");
参考输出:
Test zero length of array
msg header  is at 0x20000b88
msg content is at 0x20000b90




使用特权

评论回复
板凳
zhanzr21|  楼主 | 2020-7-19 18:13 | 只看该作者
范围case

C程序员大多写过这样的代码:
case 0:
case 1:
case 2:
....
break;
使用这个gcc扩展, 可以更方便.
void ranges(char c) {
        switch(c) {
        case '0' ... '9':
        printf("[%c] is a number.\n", c);
        break;

        case 'a' ... 'z':
        printf("[%c] is a lowercase letter.\n", c);
        break;

        case 'A' ... 'Z':
        printf("[%c] is an uppercase letter.\n", c);
        break;

        default:
                printf("[%c] is not a valid character!\n", c);
                break;
        }
}

        printf("Test case range\n");
        {
                ranges('a');
                ranges('8');
        }
        printf("\n");
参考输出:
Test case range
[a] is a lowercase letter.
[8] is a number.




使用特权

评论回复
地板
zhanzr21|  楼主 | 2020-7-19 18:14 | 只看该作者
typeof运行时推断类型

#define max(a,b) \
                ({ typeof (a) _a = (a); \
                typeof (b) _b = (b); \
                _a > _b ? _a : _b; })

    printf("Test typeof\n");
    {
        int x = 1024, y = 4096;
        char a = 10, b = 20;
        float j = 1.0, k = 2.0;

        printf("char  max is %d\n", max(a,b));
        printf("int   max is %d\n", max(x,y));
        printf("float max is %f\n", max(j,k));
    }
    printf("\n");
参考输出:
Test typeof
char  max is 20
int   max is 4096
float max is 2.000000




使用特权

评论回复
5
zhanzr21|  楼主 | 2020-7-19 18:15 | 只看该作者
空结构体

struct empty {
};

        printf("Test empty structure\n");
        printf("sizeof struct empty is %u\n", sizeof(struct empty));
        printf("\n");
参考输出:
Test empty structure
sizeof struct empty is 0




使用特权

评论回复
6
zhanzr21|  楼主 | 2020-7-19 18:17 | 只看该作者
二进制立即数, 三元操作符简化写法


这是两个扩展,用一个例子表达:
        printf("binary immediate and ternary operator\n");
        {
                int a = 10;
                int x = 0;

                a = x ? : 0b0011;

                printf("a is %d.\n", a);
        }
        printf("\n");
参考输出:
binary immediate and ternary operator
a is 3.




使用特权

评论回复
7
zhanzr21|  楼主 | 2020-7-19 18:22 | 只看该作者
以上介绍的介绍的几个GCC扩展特性, 共程序员们参考, 是否利用扩展, 取决于自己的选择.
事实上很多厂商提供的驱动代码中也有利用一些GCC扩展, 有些GCC扩展特性应用很广泛, clang, armcc等编译器也能支持. 以STM32CubeIDE为例, 可以打开-pedantic选项, 看整个工程应用了哪些gcc扩展.

打开这个选项之后, 重新build工程, 可以看到对于以上故意利用扩展的例子, 编译器会给出详细的warning.
../Core/Src/main.c:97:10: warning: ISO C forbids zero-size array 'content' [-Wpedantic]
  uint8_t content[0];
          ^~~~~~~
../Core/Src/main.c: In function 'ranges':
../Core/Src/main.c:102:2: warning: range expressions in switch statements are non-standard [-Wpedantic]
  case '0' ... '9':
  ^~~~
../Core/Src/main.c:103:2: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
  printf("[%c] is a number.\n", c);
  ^~~~~~
../Core/Src/main.c:103:2: warning: incompatible implicit declaration of built-in function 'printf'
../Core/Src/main.c:103:2: note: include '<stdio.h>' or provide a declaration of 'printf'
../Core/Src/main.c:106:2: warning: range expressions in switch statements are non-standard [-Wpedantic]
  case 'a' ... 'z':
  ^~~~
../Core/Src/main.c:110:2: warning: range expressions in switch statements are non-standard [-Wpedantic]
  case 'A' ... 'Z':
  ^~~~
../Core/Src/main.c: At top level:
../Core/Src/main.c:125:8: warning: struct has no members [-Wpedantic]
struct empty {
        ^~~~~
../Core/Src/main.c: In function 'main':
../Core/Src/main.c:137:2: warning: ISO C forbids nested functions [-Wpedantic]
  void nested_func(void) {
  ^~~~
../Core/Src/main.c: In function 'nested_func':
../Core/Src/main.c:138:3: warning: incompatible implicit declaration of built-in function 'printf'
   printf("Inside a nested function!\n");
   ^~~~~~
../Core/Src/main.c:138:3: note: include '<stdio.h>' or provide a declaration of 'printf'
../Core/Src/main.c: In function 'main':
../Core/Src/main.c:169:2: warning: incompatible implicit declaration of built-in function 'printf'
  printf("BOR: %u\n", __HAL_RCC_GET_FLAG(RCC_FLAG_BORRST));
  ^~~~~~
../Core/Src/main.c:169:2: note: include '<stdio.h>' or provide a declaration of 'printf'
../Core/Src/main.c:193:31: warning: implicit declaration of function 'malloc' [-Wimplicit-function-declaration]
   msg = (struct msg_header *) malloc(sizeof (struct msg_header) + size);
                               ^~~~~~
../Core/Src/main.c:193:31: warning: incompatible implicit declaration of built-in function 'malloc'
../Core/Src/main.c:193:31: note: include '<stdlib.h>' or provide a declaration of 'malloc'
../Core/Src/main.c:200:3: warning: implicit declaration of function 'free' [-Wimplicit-function-declaration]
   free(msg);
   ^~~~
../Core/Src/main.c:200:3: warning: incompatible implicit declaration of built-in function 'free'
../Core/Src/main.c:200:3: note: include '<stdlib.h>' or provide a declaration of 'free'
../Core/Src/main.c:121:3: warning: ISO C forbids braced-groups within expressions [-Wpedantic]
   ({ typeof (a) _a = (a); \
   ^
../Core/Src/main.c:219:31: note: in expansion of macro 'max'
   printf("char  max is %d\n", max(a,b));
                               ^~~
../Core/Src/main.c:121:3: warning: ISO C forbids braced-groups within expressions [-Wpedantic]
   ({ typeof (a) _a = (a); \
   ^
../Core/Src/main.c:220:31: note: in expansion of macro 'max'
   printf("int   max is %d\n", max(x,y));
                               ^~~
../Core/Src/main.c:121:3: warning: ISO C forbids braced-groups within expressions [-Wpedantic]
   ({ typeof (a) _a = (a); \
   ^
../Core/Src/main.c:221:31: note: in expansion of macro 'max'
   printf("float max is %f\n", max(j,k));
                               ^~~
../Core/Src/main.c:236:11: warning: ISO C forbids omitting the middle term of a ?: expression [-Wpedantic]
   a = x ? : 0b0011;
           ^
../Core/Src/main.c:236:13: warning: binary constants are a GCC extension
   a = x ? : 0b0011;
             ^~~~~~
../Core/Src/main.c:243:28: warning: format '%u' expects argument of type 'unsigned int', but argument 2 has type 'uint32_t {aka long unsigned int}' [-Wformat=]
  printf("Started ADC DMA, %u\n", SystemCoreClock);
                           ~^
                           %lu
arm-none-eabi-gcc "../Core/Src/stm32g4xx_it.c" -mcpu=cortex-m4 -std=gnu11 -g3 -DSTM32G431xx -DARM_MATH_DSP -DUSE_NUCLEO_64 -DUSE_HAL_DRIVER -DDEBUG -c -I../Drivers/STM32G4xx_HAL_Driver/Inc/Legacy -I"F:/stm32_ide_prj/stm32g431_t1_stm32ide/Core/Src/STM32G4xx_Nucleo" -I../Drivers/CMSIS/Include -I../Drivers/CMSIS/Device/ST/STM32G4xx/Include -I../Core/Inc -I../Drivers/STM32G4xx_HAL_Driver/Inc -O0 -ffunction-sections -fdata-sections -Wall -pedantic -fstack-usage -MMD -MP -MF"Core/Src/stm32g4xx_it.d" -MT"Core/Src/stm32g4xx_it.o" --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -o "Core/Src/stm32g4xx_it.o"
arm-none-eabi-gcc "../Core/Src/syscalls.c" -mcpu=cortex-m4 -std=gnu11 -g3 -DSTM32G431xx -DARM_MATH_DSP -DUSE_NUCLEO_64 -DUSE_HAL_DRIVER -DDEBUG -c -I../Drivers/STM32G4xx_HAL_Driver/Inc/Legacy -I"F:/stm32_ide_prj/stm32g431_t1_stm32ide/Core/Src/STM32G4xx_Nucleo" -I../Drivers/CMSIS/Include -I../Drivers/CMSIS/Device/ST/STM32G4xx/Include -I../Core/Inc -I../Drivers/STM32G4xx_HAL_Driver/Inc -O0 -ffunction-sections -fdata-sections -Wall -pedantic -fstack-usage -MMD -MP -MF"Core/Src/syscalls.d" -MT"Core/Src/syscalls.o" --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -o "Core/Src/syscalls.o"
arm-none-eabi-gcc "../Core/Src/sysmem.c" -mcpu=cortex-m4 -std=gnu11 -g3 -DSTM32G431xx -DARM_MATH_DSP -DUSE_NUCLEO_64 -DUSE_HAL_DRIVER -DDEBUG -c -I../Drivers/STM32G4xx_HAL_Driver/Inc/Legacy -I"F:/stm32_ide_prj/stm32g431_t1_stm32ide/Core/Src/STM32G4xx_Nucleo" -I../Drivers/CMSIS/Include -I../Drivers/CMSIS/Device/ST/STM32G4xx/Include -I../Core/Inc -I../Drivers/STM32G4xx_HAL_Driver/Inc -O0 -ffunction-sections -fdata-sections -Wall -pedantic -fstack-usage -MMD -MP -MF"Core/Src/sysmem.d" -MT"Core/Src/sysmem.o" --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -o "Core/Src/sysmem.o"
arm-none-eabi-gcc "../Core/Src/system_stm32g4xx.c" -mcpu=cortex-m4 -std=gnu11 -g3 -DSTM32G431xx -DARM_MATH_DSP -DUSE_NUCLEO_64 -DUSE_HAL_DRIVER -DDEBUG -c -I../Drivers/STM32G4xx_HAL_Driver/Inc/Legacy -I"F:/stm32_ide_prj/stm32g431_t1_stm32ide/Core/Src/STM32G4xx_Nucleo" -I../Drivers/CMSIS/Include -I../Drivers/CMSIS/Device/ST/STM32G4xx/Include -I../Core/Inc -I../Drivers/STM32G4xx_HAL_Driver/Inc -O0 -ffunction-sections -fdata-sections -Wall -pedantic -fstack-usage -MMD -MP -MF"Core/Src/system_stm32g4xx.d" -MT"Core/Src/system_stm32g4xx.o" --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -o "Core/Src/system_stm32g4xx.o"
arm-none-eabi-gcc "../Core/Src/usart.c" -mcpu=cortex-m4 -std=gnu11 -g3 -DSTM32G431xx -DARM_MATH_DSP -DUSE_NUCLEO_64 -DUSE_HAL_DRIVER -DDEBUG -c -I../Drivers/STM32G4xx_HAL_Driver/Inc/Legacy -I"F:/stm32_ide_prj/stm32g431_t1_stm32ide/Core/Src/STM32G4xx_Nucleo" -I../Drivers/CMSIS/Include -I../Drivers/CMSIS/Device/ST/STM32G4xx/Include -I../Core/Inc -I../Drivers/STM32G4xx_HAL_Driver/Inc -O0 -ffunction-sections -fdata-sections -Wall -pedantic -fstack-usage -MMD -MP -MF"Core/Src/usart.d" -MT"Core/Src/usart.o" --specs=nano.specs -mfpu=fpv4-sp-d16 -mfloat-abi=hard -mthumb -o "Core/Src/usart.o"
../Core/Src/syscalls.c:41:1: warning: file-scope declaration of 'stack_ptr' specifies 'register' [-Wpedantic]
register char * stack_ptr asm("sp");
^~~~~~~~
../Core/Src/sysmem.c:30:1: warning: file-scope declaration of 'stack_ptr' specifies 'register' [-Wpedantic]
register char * stack_ptr asm("sp");
^~~~~~~~




使用特权

评论回复
8
zhanzr21|  楼主 | 2020-7-19 18:24 | 只看该作者
除此之外, 还可以完全禁止gcc扩展, 这样工程就需要改很多代码, 因为厂商提供的驱动库也会依赖某些gcc扩展特性.

../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_ll_adc.c:1336:0: error: ISO C forbids an empty translation unit [-Wpedantic]
../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_ll_pwr.c:86:0: error: ISO C forbids an empty translation unit [-Wpedantic]
make: *** [Drivers/STM32G4xx_HAL_Driver/Src/subdir.mk:133: Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_ll_pwr.o] Error 1
make: *** Waiting for unfinished jobs....
make: *** [Drivers/STM32G4xx_HAL_Driver/Src/subdir.mk:131: Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_ll_adc.o] Error 1
如果要完全禁止gcc扩展特性, 以上错误必须修复.

本贴完, 谢谢阅读!


使用特权

评论回复
9
天灵灵地灵灵| | 2020-7-20 23:56 | 只看该作者
给力,以前好像真的没这功能。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:每天都進步

91

主题

1013

帖子

34

粉丝