cl x64:无符号长外部/内部联合:错误C2099:初始化程序不是常量/没有错误

情况1。文件:test1.c

unsigned long val = (unsigned long)&"test";

int main() 
{
    return 0;
}

编译器调用:cl test1.c /c

结果:

microsoft (R) C/C++ Optimizing Compiler Version 19.25.28611 for x64
Copyright (C) microsoft Corporation.  All rights reserved.

test1.c
test1.c(1): warning C4311: 'type cast': pointer truncation from 'char (*)[5]' to 'unsigned long'
test1.c(1): error C2099: initializer is not a constant

情况2。文件:test2.c

union { unsigned long val; } val =  { (unsigned long)&"test" };

int main() 
{
    return 0;
}

编译器调用:cl test2.c /c

结果:

microsoft (R) C/C++ Optimizing Compiler Version 19.25.28611 for x64
Copyright (C) microsoft Corporation.  All rights reserved.

test2.c
test2.c(1): warning C4311: 'type cast': pointer truncation from 'char (*)[5]' to 'unsigned long'

问题:为什么将unsigned long放入union(案例2,文件test2.c)之后,error C2099: initializer is not a constant消失了?

注意:

    对于两个代码版本cl x86(与x64相同的版本),
  • 都不会产生错误,也不会发出警告。

  • 两种代码版本gcc x86/x64(版本9.3.0)的
  • 都不会产生错误,也不会发出警告。

UPD。请注意:问题与safe code / unsafe codewrong code / right code有关。问题是关于cl编译器的行为。即为什么在第二种情况下,cl认为initializer IS a constant(这种结论是由于没有错误消息)。

iCMS 回答:cl x64:无符号长外部/内部联合:错误C2099:初始化程序不是常量/没有错误

静态存储持续时间对象的初始化程序必须是恒定表达式

在C89标准(Microsoft C conforms唯一的标准)中,常量表达式中不允许将指针强制转换为整数。

这是一个语义规则,而不是约束条件,这意味着程序具有未定义的行为,而无需诊断。因此,允许编译器拒绝该程序(但不要求拒绝该程序),它可能会也可能不会发出诊断信息,并且未定义的各种程序之间没有一致性要求。

我们不能从没有错误消息的结论中得出初始化器被接受为常量的结论。

自C99以来,该标准还包括文本“实现可以接受其他形式的常量表达式”。尽管我找不到MSVC的文档,但编译器应该发布一致性文档,列出其接受为常量的表达式。 (如果可以的话,发表评论!)

请注意有关将指针强制转换为unsigned long的规则。根据最新标准:

任何指针类型都可以转换为整数类型。除先前指定外, 结果是实现定义的。如果结果无法以整数类型表示, 行为是不确定的。结果不必在任何整数的值范围内 类型。

因此,即使C99或C11兼容的编译器说明它接受常量表达式中从指针到整数的强制转换,强制转换的结果仍可能会导致启动时出现陷阱或导致未定义的行为(其中,像以前一样,意味着不需要诊断,并且该程序可能会被拒绝。)

本文链接:https://www.f2er.com/2217789.html

大家都在问