gcc 里定义数组时如果长度是浮点运算结果会报 variably modified 'xxx' at file scope 警告,有没有办法能消除警告?

2023-04-06 14:56:48 +08:00
 wudicgi

像这样一段代码

#include <stdio.h>

// 100.0 / 27.0 = 3.7037 -> (int)3
#define BUFFER_SIZE   ((int)((double)100 / (double)27))

// sizeof(_buffer) = 3
unsigned char _buffer[BUFFER_SIZE];

int main(void) {
    printf("Hello World, sizeof(buffer) = %u\n", (unsigned int)sizeof(_buffer));

    return 0;
}

MSVC 编译器不会报任何警告, clang 通过加 -Wno-gnu-folding-constant 参数也能消除警告。

gcc 会在 _buffer 数组定义这一行报 warning: variably modified '_buffer' at file scope, 始终没找到啥办法能让它不报这个警告,只能把表达式改成整数运算形式的。

1753 次点击
所在节点    C
11 条回复
wudicgi
2023-04-06 14:59:45 +08:00
以下是在在线编译器中编译的结果:

gcc 12.2 // 尚未找到解决办法
https://godbolt.org/z/a7sG88ooa

<source>:7:1: error: variably modified '_buffer' at file scope [-Werror]
7 | unsigned char _buffer[BUFFER_SIZE];
| ^~~~~~~~

clang 16.0.0 // 添加 -Wno-gnu-folding-constant 编译参数后警告可被去除
https://godbolt.org/z/GWEoWMsvv

<source>:7:15: error: variable length array folded to constant array as an extension [-Werror,-Wgnu-folding-constant]
unsigned char _buffer[BUFFER_SIZE];
^

msvc 19.33 // 没有任何警告或错误
https://godbolt.org/z/nME5W553d
ysc3839
2023-04-06 16:11:54 +08:00
怀疑是被当成 VLA ?尝试禁用 VLA ?
如果是 C++的话可以考虑用 std::integral_constant 包一层
lakehylia
2023-04-06 16:28:55 +08:00
你这个为啥还要转成 double 再转 int 啊,直接 #define BUFFER_SIZE (100/27) 不就行了?或者 static const int BUFFER_SIZE = 100/27;
整型的除法结果就是商啊。
wudicgi
2023-04-06 17:07:00 +08:00
@ysc3839 这种情况应该也是被当成 VLA 了,我改成指定 -std=c11 -Werror=vla 参数后,提示信息变为:

<source>:7:1: warning: variably modified '_buffer' at file scope
7 | unsigned char _buffer[BUFFER_SIZE];
| ^~~~~~~~
<source>:7:1: error: ISO C90 forbids array '_buffer' whose size cannot be evaluated [-Werror=vla]
cc1: some warnings being treated as errors

不过查到结果是 gcc 里不能禁用 VLA 支持。
wudicgi
2023-04-06 17:08:28 +08:00
@lakehylia 这里为了方便看到核心问题,就放了个最简单的表达式。
实际的表达式有好几层括号,还有 (int)(x + 0.5) 这样实现四舍五入的部分,改成整数运算的表达式看着就会非常不直观。
lakehylia
2023-04-06 17:19:53 +08:00
我在 mac 上面用 clang 和 gcc 没有任何警告啊,用 cpp 文件编译的
wudicgi
2023-04-06 17:27:16 +08:00
为了防止被认为可能是 X-Y 问题,我再贴一下原始问题。

如果可以正常用浮点数运算,再转成整数作为数组大小,那么我可以使用:
#define CONFIG_SLICE_COUNT_PER_SECOND ((double)((double)11025 / (double)63))
#define HALF_HANN_200MS_LENGTH ((int)(((CONFIG_SLICE_COUNT_PER_SECOND * 0.2) / 2) + 0.5))

如果为了避开这个警告信息,全部使用整数运算,那么我需要这样写:
#define CONFIG_SLICE_COUNT_PER_SECOND (11025 / 63) // 恰好能被整除
#define HALF_HANN_200MS_LENGTH ((((CONFIG_SLICE_COUNT_PER_SECOND * 2) / 10) + 1) / 2)

就非常不直观,虽然对于 200ms -> 0.2s, +0.5 实现四舍五入这些我可以再写一些宏把它包装起来,
但对于 11025 / 63 这种地方,如果不是恰好能被整除的话就还是有额外的问题,不处理会损失一些精度。
cnbatch
2023-04-06 17:28:52 +08:00
@lakehylia cpp 后缀改成 c (也就是使用纯 C ),就能复现了
wudicgi
2023-04-06 17:36:08 +08:00
@lakehylia 我开始进 godbolt.org 的时候,默认语言是 C++, 编译器选择 gcc 确实没有这个警告,把语言换成 C 之后就有了。

现在默认编译时是调用的 gcc 不是 g++, 能否改成用 g++ 编译我再看看。
因为现在问题主要在发生在编译 ESP32 固件时,它的 SDK 默认调用的是 xtensa-esp32-elf-gcc.exe
ysc3839
2023-04-06 19:40:50 +08:00
@wudicgi 不确定 ESP32 是否支持 C++,但是 Arduino 是支持的。建议改用 C++。
TripleLens
2023-04-07 11:23:26 +08:00
试了一下用枚举常量就没有警告,这里行为可能有点不一致

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/930269

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX