“来自指针的整数/整数的指针没有强制转换”问题

这个问题是整数和指针问题之间所有初始化/赋值的FAQ条目。


我想写一个指针设置为特定内存地址的代码,例如0x12345678 。 但是当用gcc编译器编译这个代码时,我得到“初始化使得整数没有强制转换的指针”警告/错误:

 int* p = 0x12345678; 

类似地,这段代码给出了“初始化从没有强制转换的指针生成整数”:

 int* p = ...; int i = p; 

如果我在变量声明行之外做同样的事情,那么消息是相同的但是说“赋值”而不是“初始化”:

 p = 0x12345678; // "assignment makes pointer from integer without a cast" i = p; // "assignment makes integer from pointer without a cast" 

其他流行编译器的测试也会给出错误/警告消息:

  • clang说“指针转换不兼容的整数”
  • icc说“ int类型的值不能用于初始化int*类型的实体”
  • MSVC(cl)说“初始化int*int*的间接级别不同”。

问题:以上示例是否有效?


还有一个后续问题:

这不会给出任何警告/错误:

 int* p = 0; 

为什么不?

不,它不是有效的C并且从未有效C.这些示例是所谓的约束违反标准。

该标准不允许您初始化/分配指向整数的指针,也不允许指定整数指针。 您需要使用强制转换手动强制进行类型转换:

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

如果不使用强制转换,则代码无效C,并且不允许编译器在不显示消息的情况下通过代码。 具体而言,这是由简单分配规则C176.5.16.1§1规定的:

6.5.16.1简单分配

约束

以下其中一项应持有:

  • 左操作数具有primefaces,限定或非限定算术类型,右边有算术类型;
  • 左操作数具有与右侧类型兼容的结构或联合类型的primefaces,限定或非限定版本;
  • 左操作数具有primefaces,限定或非限定指针类型,并且(考虑左值操作数在左值转换后将具有的类型)两个操作数都是指向兼容类型的限定或非限定版本的指针,左侧指向的类型具有全部右边指出的类型的限定词;
  • 左操作数具有primefaces,限定或非限定指针类型,并且(考虑左值操作数在左值转换后将具有的类型)一个操作数是指向对象类型的指针,另一个是指向合格或非限定版本的指针void,左边指向的类型具有右边指向的所有类型的限定符;
  • 左操作数是一个primefaces,限定或非限定指针,右边是一个空指针常量; 要么
  • 左操作数的类型为atomic,qualified或nonqualified _Bool,右边是指针。

int* p = 0x12345678;情况下int* p = 0x12345678; ,左操作数是指针,右边是算术类型。
int i = p;情况下int i = p; ,左操作数是算术类型,右边是指针。
这些都不符合上述任何限制。

至于为什么int* p = 0; 工作,这是一个特例。 左操作数是一个指针,右边是一个空指针常量 。 有关空指针,空指针常量和NULL宏之间差异的更多信息 。


有些注意事项:

  • 如果为指针分配原始地址,则指针可能需要是volatile限定的,因为它指向类似硬件寄存器或EEPROM /闪存位置的东西,可以在运行时更改其内容。

  • 即使使用强制转换,也不能保证将指针转换为整数。 标准(C176.3.2.3§5和§6说):

    整数可以转换为任何指针类型。 除非先前指定,否则结果是实现定义的,可能未正确对齐,可能不指向引用类型的实体,并且可能是陷阱表示。 68)

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

    信息脚注:

    68)用于将指针转换为整数或整数到指针的映射函数旨在与执行环境的寻址结构一致。

    此外,指针的地址可能大于int ,就像大多数64位系统的情况一样。 因此,最好使用uintptr_t