cl x64: unsigned long outside / inside union: error C2099: initializer is not a constant / NO error

老子叫甜甜 提交于 2021-01-27 19:50:17

问题


Case 1. File: test1.c:

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

int main() 
{
    return 0;
}

Compiler invocation: cl test1.c /c

Results:

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

Case 2. File: test2.c:

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

int main() 
{
    return 0;
}

Compiler invocation: cl test2.c /c

Results:

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'

Question: why after putting unsigned long into union (case 2, file test2.c) the error C2099: initializer is not a constant is gone?

Notes:

  • for both code versions cl x86 (same version as for x64) produces NO errors, NO warnings.

  • for both code versions gcc x86/x64 (version 9.3.0) produces NO errors, NO warnings.

UPD. Please note: the question is not about safe code / unsafe code or wrong code / right code. The question is about cl compiler behavior. I.e. why in the 2nd case the cl considers that initializer IS a constant (such conclusion is from the absence of the error message).


回答1:


Initializers for objects of static storage duration must be constant expressions .

In the C89 standard (the only standard to which Microsoft C conforms) , a cast from pointer to integer is not permitted in a constant expression.

This is a Semantic rule and not a Constraint, which means the program has undefined behaviour with no diagnostic required. Therefore the compiler is permitted to reject the program (but is not required to reject it), it may or may not issue diagnostics, and there is no requirement of consistency amongst various programs that are undefined.

We cannot conclude from the absence of an Error message that the initializer was accepted as a constant .

Since C99, the standard also includes the text "An implementation may accept other forms of constant expressions". The compiler should publish conformance documentation listing which expressions it accepts as constants, although I couldn't find that documentation for MSVC. (leave a comment if you can!)

It may also be relevant to note the rules about casting pointer to unsigned long. From the latest Standard:

Any pointer type may be converted to an integer type. Except as previously specified, the result is implementation-defined. If the result cannot be represented in the integer type, the behavior is undefined. The result need not be in the range of values of any integer type.

So, even if the C99 or C11-compliant compiler documents that it accepts casts from pointer to integer in constant expressions, it may still be that the result of the cast causes a trap on startup, or causes undefined behaviour (which , as before, means no diagnostic is required and the program may be rejected).



来源:https://stackoverflow.com/questions/62160814/cl-x64-unsigned-long-outside-inside-union-error-c2099-initializer-is-not-a

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!