V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
wudicgi
V2EX  ›  C

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

  •  
  •   wudicgi · 357 天前 · 1429 次点击
    这是一个创建于 357 天前的主题,其中的信息可能已经有所发展或是发生改变。

    像这样一段代码

    #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, 始终没找到啥办法能让它不报这个警告,只能把表达式改成整数运算形式的。

    11 条回复    2023-04-07 11:23:26 +08:00
    wudicgi
        1
    wudicgi  
    OP
       357 天前
    以下是在在线编译器中编译的结果:

    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
        2
    ysc3839  
       357 天前 via Android
    怀疑是被当成 VLA ?尝试禁用 VLA ?
    如果是 C++的话可以考虑用 std::integral_constant 包一层
    lakehylia
        3
    lakehylia  
       357 天前
    你这个为啥还要转成 double 再转 int 啊,直接 #define BUFFER_SIZE (100/27) 不就行了?或者 static const int BUFFER_SIZE = 100/27;
    整型的除法结果就是商啊。
    wudicgi
        4
    wudicgi  
    OP
       357 天前
    @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
        5
    wudicgi  
    OP
       357 天前
    @lakehylia 这里为了方便看到核心问题,就放了个最简单的表达式。
    实际的表达式有好几层括号,还有 (int)(x + 0.5) 这样实现四舍五入的部分,改成整数运算的表达式看着就会非常不直观。
    lakehylia
        6
    lakehylia  
       357 天前
    我在 mac 上面用 clang 和 gcc 没有任何警告啊,用 cpp 文件编译的
    wudicgi
        7
    wudicgi  
    OP
       357 天前
    为了防止被认为可能是 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
        8
    cnbatch  
       357 天前
    @lakehylia cpp 后缀改成 c (也就是使用纯 C ),就能复现了
    wudicgi
        9
    wudicgi  
    OP
       357 天前
    @lakehylia 我开始进 godbolt.org 的时候,默认语言是 C++, 编译器选择 gcc 确实没有这个警告,把语言换成 C 之后就有了。

    现在默认编译时是调用的 gcc 不是 g++, 能否改成用 g++ 编译我再看看。
    因为现在问题主要在发生在编译 ESP32 固件时,它的 SDK 默认调用的是 xtensa-esp32-elf-gcc.exe
    ysc3839
        10
    ysc3839  
       357 天前 via Android
    @wudicgi 不确定 ESP32 是否支持 C++,但是 Arduino 是支持的。建议改用 C++。
    TripleLens
        11
    TripleLens  
       356 天前
    试了一下用枚举常量就没有警告,这里行为可能有点不一致
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   3249 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 27ms · UTC 13:57 · PVG 21:57 · LAX 06:57 · JFK 09:57
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.