[开发工具] GCC对C语言的几个扩展

[复制链接]
967|8
 楼主| zhanzr21 发表于 2020-7-19 18:07 | 显示全部楼层 |阅读模式
本帖最后由 zhanzr21 于 2020-7-19 18:11 编辑

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

内嵌函数

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

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






 楼主| zhanzr21 发表于 2020-7-19 18:10 | 显示全部楼层
0长度数组

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

  1. struct msg_header {
  2.         uint32_t type;
  3.         uint32_t size;
  4.         uint8_t content[0];
  5. };


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

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

  11.                 msg->type = 0x01;
  12.                 msg->size = size;

  13.                 printf("msg header  is at %p\n", (void *)msg);
  14.                 printf("msg content is at %p\n", (void *)msg->content);
  15.                 free(msg);
  16.         }
  17.         printf("\n");
参考输出:
  1. Test zero length of array
  2. msg header  is at 0x20000b88
  3. msg content is at 0x20000b90




 楼主| zhanzr21 发表于 2020-7-19 18:13 | 显示全部楼层
范围case

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

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

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

  12.         default:
  13.                 printf("[%c] is not a valid character!\n", c);
  14.                 break;
  15.         }
  16. }

  17.         printf("Test case range\n");
  18.         {
  19.                 ranges('a');
  20.                 ranges('8');
  21.         }
  22.         printf("\n");
参考输出:
  1. Test case range
  2. [a] is a lowercase letter.
  3. [8] is a number.




 楼主| zhanzr21 发表于 2020-7-19 18:14 | 显示全部楼层
typeof运行时推断类型

  1. #define max(a,b) \
  2.                 ({ typeof (a) _a = (a); \
  3.                 typeof (b) _b = (b); \
  4.                 _a > _b ? _a : _b; })

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

  10.         printf("char  max is %d\n", max(a,b));
  11.         printf("int   max is %d\n", max(x,y));
  12.         printf("float max is %f\n", max(j,k));
  13.     }
  14.     printf("\n");
参考输出:
  1. Test typeof
  2. char  max is 20
  3. int   max is 4096
  4. float max is 2.000000




 楼主| zhanzr21 发表于 2020-7-19 18:15 | 显示全部楼层
空结构体

  1. struct empty {
  2. };

  3.         printf("Test empty structure\n");
  4.         printf("sizeof struct empty is %u\n", sizeof(struct empty));
  5.         printf("\n");
参考输出:
  1. Test empty structure
  2. sizeof struct empty is 0




 楼主| zhanzr21 发表于 2020-7-19 18:17 | 显示全部楼层
二进制立即数, 三元操作符简化写法


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

  5.                 a = x ? : 0b0011;

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




 楼主| zhanzr21 发表于 2020-7-19 18:22 | 显示全部楼层
以上介绍的介绍的几个GCC扩展特性, 共程序员们参考, 是否利用扩展, 取决于自己的选择.
事实上很多厂商提供的驱动代码中也有利用一些GCC扩展, 有些GCC扩展特性应用很广泛, clang, armcc等编译器也能支持. 以STM32CubeIDE为例, 可以打开-pedantic选项, 看整个工程应用了哪些gcc扩展.
pedantic_warning_enable.png
打开这个选项之后, 重新build工程, 可以看到对于以上故意利用扩展的例子, 编译器会给出详细的warning.
  1. ../Core/Src/main.c:97:10: warning: ISO C forbids zero-size array 'content' [-Wpedantic]
  2.   uint8_t content[0];
  3.           ^~~~~~~
  4. ../Core/Src/main.c: In function 'ranges':
  5. ../Core/Src/main.c:102:2: warning: range expressions in switch statements are non-standard [-Wpedantic]
  6.   case '0' ... '9':
  7.   ^~~~
  8. ../Core/Src/main.c:103:2: warning: implicit declaration of function 'printf' [-Wimplicit-function-declaration]
  9.   printf("[%c] is a number.\n", c);
  10.   ^~~~~~
  11. ../Core/Src/main.c:103:2: warning: incompatible implicit declaration of built-in function 'printf'
  12. ../Core/Src/main.c:103:2: note: include '<stdio.h>' or provide a declaration of 'printf'
  13. ../Core/Src/main.c:106:2: warning: range expressions in switch statements are non-standard [-Wpedantic]
  14.   case 'a' ... 'z':
  15.   ^~~~
  16. ../Core/Src/main.c:110:2: warning: range expressions in switch statements are non-standard [-Wpedantic]
  17.   case 'A' ... 'Z':
  18.   ^~~~
  19. ../Core/Src/main.c: At top level:
  20. ../Core/Src/main.c:125:8: warning: struct has no members [-Wpedantic]
  21. struct empty {
  22.         ^~~~~
  23. ../Core/Src/main.c: In function 'main':
  24. ../Core/Src/main.c:137:2: warning: ISO C forbids nested functions [-Wpedantic]
  25.   void nested_func(void) {
  26.   ^~~~
  27. ../Core/Src/main.c: In function 'nested_func':
  28. ../Core/Src/main.c:138:3: warning: incompatible implicit declaration of built-in function 'printf'
  29.    printf("Inside a nested function!\n");
  30.    ^~~~~~
  31. ../Core/Src/main.c:138:3: note: include '<stdio.h>' or provide a declaration of 'printf'
  32. ../Core/Src/main.c: In function 'main':
  33. ../Core/Src/main.c:169:2: warning: incompatible implicit declaration of built-in function 'printf'
  34.   printf("BOR: %u\n", __HAL_RCC_GET_FLAG(RCC_FLAG_BORRST));
  35.   ^~~~~~
  36. ../Core/Src/main.c:169:2: note: include '<stdio.h>' or provide a declaration of 'printf'
  37. ../Core/Src/main.c:193:31: warning: implicit declaration of function 'malloc' [-Wimplicit-function-declaration]
  38.    msg = (struct msg_header *) malloc(sizeof (struct msg_header) + size);
  39.                                ^~~~~~
  40. ../Core/Src/main.c:193:31: warning: incompatible implicit declaration of built-in function 'malloc'
  41. ../Core/Src/main.c:193:31: note: include '<stdlib.h>' or provide a declaration of 'malloc'
  42. ../Core/Src/main.c:200:3: warning: implicit declaration of function 'free' [-Wimplicit-function-declaration]
  43.    free(msg);
  44.    ^~~~
  45. ../Core/Src/main.c:200:3: warning: incompatible implicit declaration of built-in function 'free'
  46. ../Core/Src/main.c:200:3: note: include '<stdlib.h>' or provide a declaration of 'free'
  47. ../Core/Src/main.c:121:3: warning: ISO C forbids braced-groups within expressions [-Wpedantic]
  48.    ({ typeof (a) _a = (a); \
  49.    ^
  50. ../Core/Src/main.c:219:31: note: in expansion of macro 'max'
  51.    printf("char  max is %d\n", max(a,b));
  52.                                ^~~
  53. ../Core/Src/main.c:121:3: warning: ISO C forbids braced-groups within expressions [-Wpedantic]
  54.    ({ typeof (a) _a = (a); \
  55.    ^
  56. ../Core/Src/main.c:220:31: note: in expansion of macro 'max'
  57.    printf("int   max is %d\n", max(x,y));
  58.                                ^~~
  59. ../Core/Src/main.c:121:3: warning: ISO C forbids braced-groups within expressions [-Wpedantic]
  60.    ({ typeof (a) _a = (a); \
  61.    ^
  62. ../Core/Src/main.c:221:31: note: in expansion of macro 'max'
  63.    printf("float max is %f\n", max(j,k));
  64.                                ^~~
  65. ../Core/Src/main.c:236:11: warning: ISO C forbids omitting the middle term of a ?: expression [-Wpedantic]
  66.    a = x ? : 0b0011;
  67.            ^
  68. ../Core/Src/main.c:236:13: warning: binary constants are a GCC extension
  69.    a = x ? : 0b0011;
  70.              ^~~~~~
  71. ../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=]
  72.   printf("Started ADC DMA, %u\n", SystemCoreClock);
  73.                            ~^
  74.                            %lu
  75. 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"
  76. 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"
  77. 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"
  78. 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"
  79. 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"
  80. ../Core/Src/syscalls.c:41:1: warning: file-scope declaration of 'stack_ptr' specifies 'register' [-Wpedantic]
  81. register char * stack_ptr asm("sp");
  82. ^~~~~~~~
  83. ../Core/Src/sysmem.c:30:1: warning: file-scope declaration of 'stack_ptr' specifies 'register' [-Wpedantic]
  84. register char * stack_ptr asm("sp");
  85. ^~~~~~~~




 楼主| zhanzr21 发表于 2020-7-19 18:24 | 显示全部楼层
除此之外, 还可以完全禁止gcc扩展, 这样工程就需要改很多代码, 因为厂商提供的驱动库也会依赖某些gcc扩展特性.
pedantic_warning_error_enable.png
  1. ../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_ll_adc.c:1336:0: error: ISO C forbids an empty translation unit [-Wpedantic]
  2. ../Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_ll_pwr.c:86:0: error: ISO C forbids an empty translation unit [-Wpedantic]
  3. make: *** [Drivers/STM32G4xx_HAL_Driver/Src/subdir.mk:133: Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_ll_pwr.o] Error 1
  4. make: *** Waiting for unfinished jobs....
  5. make: *** [Drivers/STM32G4xx_HAL_Driver/Src/subdir.mk:131: Drivers/STM32G4xx_HAL_Driver/Src/stm32g4xx_ll_adc.o] Error 1
如果要完全禁止gcc扩展特性, 以上错误必须修复.

本贴完, 谢谢阅读!


天灵灵地灵灵 发表于 2020-7-20 23:56 | 显示全部楼层
给力,以前好像真的没这功能。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:每天都進步

91

主题

1018

帖子

34

粉丝
快速回复 在线客服 返回列表 返回顶部