“Pointer from integer/integer from pointer without a cast” issues

后端 未结 1 2060
无人共我
无人共我 2020-11-22 13:38

This question is meant to be a FAQ entry for all initialization/assignment between integer and pointer issues.


I want to do write code where a pointer

相关标签:
1条回答
  • 2020-11-22 14:03

    No, it is not valid C and have never been valid C. These examples are so-called constraint violation of the standard.

    The standard does not allow you to initialize/assign a pointer to an integer, nor an integer to a pointer. You need to manually force a type conversion with a cast:

    int* p = (int*) 0x1234;
    
    int i = (int)p;
    

    If you don't use the cast, the code is not valid C and your compiler is not allowed to let the code pass without displaying a message. Specifically, this is regulated by the rules of simple assignment, C17 6.5.16.1 §1:

    6.5.16.1 Simple assignment

    Constraints

    One of the following shall hold:

    • the left operand has atomic, qualified, or unqualified arithmetic type, and the right has arithmetic type;
    • the left operand has an atomic, qualified, or unqualified version of a structure or union type compatible with the type of the right;
    • the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) both operands are pointers to qualified or unqualified versions of compatible types, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
    • the left operand has atomic, qualified, or unqualified pointer type, and (considering the type the left operand would have after lvalue conversion) one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void, and the type pointed to by the left has all the qualifiers of the type pointed to by the right;
    • the left operand is an atomic, qualified, or unqualified pointer, and the right is a null pointer constant; or
    • the left operand has type atomic, qualified, or unqualified _Bool, and the right is a pointer.

    In case of int* p = 0x12345678;, the left operand is a pointer and the right is an arithmetic type.
    In case of int i = p;, the left operand is an arithmetic type and the right is a pointer.
    Neither of these fit in with any of the constraints cited above.

    As for why int* p = 0; works, it is a special case. The left operand is a pointer and the right is a null pointer constant. More info about the difference between null pointers, null pointer constants and the NULL macro.


    Some things of note:

    • If you assign a raw address to a pointer, the pointer likely need to be volatile qualified, given that it points at something like a hardware register or an EEPROM/Flash memory location, that can change its contents in run-time.

    • Converting a pointer to an integer is by no means guaranteed to work even with the cast. The standard (C17 6.3.2.3 §5 and §6 says):

      An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation. 68)

      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.

      Informative foot note:

      68) The mapping functions for converting a pointer to an integer or an integer to a pointer are intended to be consistent with the addressing structure of the execution environment.

      In addition, the address from a pointer might be larger than what will fit inside an int, as is the case for most 64 bit systems. Therefore it is better to use the uintptr_t from <stdint.h>

    0 讨论(0)
提交回复
热议问题