问题描述:

Im not entirely sure whether or not the following brakes the C standard, but clang allows one to initialize static const scalar typed variables with the contents of another static const scalar variable, example:

static const long temp = 10;

static const long temp1 = temp;

when I try with pointers, it fails.

static const long *const temp = (void *)1000; // ok

static const long *const temp2 = (void *)&temp2; // ok

static const long *const temp1 = temp;

// ^^^^ error: initializer element is not a compile-time constant

one way to over come this would be to simply use long or any other scalar type large enough to hold addresses ...

static unsigned long long temp;

static const unsigned long long addr = (unsigned long long)&temp;

static const unsigned long long addr2 = addr;

this sounds horrible not to mention Im not entirely sure how safe it is, since I don't know if the linker/loader can/will update addresses ...

any ideas as to how or even if it is possible to initialize a static const pointer with the contents of another static const pointer ... to be more precise I was trying with function pointers, but noticed the same thing with other pointer types ...

网友答案:

Here is the text covering this:

C11 6.6/7:

More latitude is permitted for constant expressions in initializers. Such a constant expression shall be, or evaluate to, one of the following:

  • an arithmetic constant expression,
  • a null pointer constant,
  • an address constant, or
  • an address constant for a complete object type plus or minus an integer constant expression.

C11 6.6/9:

An address constant is a null pointer, a pointer to an lvalue designating an object of static storage duration, or a pointer to a function designator; it shall be created explicitly using the unary & operator or an integer constant cast to pointer type, or implicitly by the use of an expression of array or function type. The array-subscript [] and member-access . and -> operators, the address & and indirection * unary operators, and pointer casts may be used in the creation of an address constant, but the value of an object shall not be accessed by use of these operators.

C11 6.6/10:

An implementation may accept other forms of constant expressions.

So, your temp does not qualify to be an address constant because it doesn't satisfy any of the options in the definition of address constant.

Rationale: IDK, it seems like an oversight to me. Perhaps it is to avoid placing undue burden on the compiler; e.g. if (void *)1000 does not actually point to an object (e.g. it points outside the process's address space, or is a trap representation), then evaluating temp causes undefined behaviour (no diagnostic required).

Workaround: Using unsigned long long is not as good as using uintptr_t. However ,

static const long *const temp1 = (void *)1000; 

seems like a better option than the integer options. You could use a #define macro to avoid repeating the actual address.

相关阅读:
Top