简体   繁体   English

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

[英]"Pointer from integer/integer from pointer without a cast" issues

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 is set to a specific memory address, for example 0x12345678 .我想编写代码,将指针设置为特定的内存地址,例如0x12345678 But when compiling this code with the gcc compiler, I get "initialization makes pointer from integer without a cast" warnings/errors:但是当用 gcc 编译器编译这段代码时,我得到“初始化使指针从整数而不进行强制转换”警告/错误:

int* p = 0x12345678;

Similarly, this code gives "initialization makes integer from pointer without a cast":类似地,这段代码给出了“初始化从指针生成整数而不进行强制转换”:

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

If I do the same outside the line of variable declaration, the message is the same but says "assignment" instead of "initialization":如果我在变量声明行之外做同样的事情,消息是一样的,但说的是“赋值”而不是“初始化”:

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

Tests with other popular compilers also give error/warning messages:使用其他流行编译器的测试也会给出错误/警告消息:

  • clang says "incompatible integer to pointer conversion" clang 说“不兼容的整数到指针转换”
  • icc says "a value of type int cannot be used to initialize an entity of type int* " icc 说“ int类型的值不能用于初始化int*类型的实体”
  • MSVC (cl) says "initializing int* differs in levels of indirection from int ". MSVC(CL)说:“初始化int*的不同之处,从间接的水平int ”。

Question: Are the above examples valid C?问题:上面的例子是有效的 C 吗?


And a follow-up question:还有一个后续问题:

This does not give any warnings/errors:这不会给出任何警告/错误:

int* p = 0;

Why not?为什么不?

No, it is not valid C and has never been valid C. These examples are so-called constraint violations of the standard.不,它不是有效的 C 并且从来都不是有效的 C。这些例子是所谓的违反标准的约束

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.如果您不使用强制转换,则代码不是有效的 C,并且您的编译器不允许在不显示消息的情况下让代码通过。 Specifically, this is regulated by the rules of simple assignment , C17 6.5.16.1 §1:具体来说,这是由简单分配规则,C17 6.5.16.1 §1 规定的:

6.5.16.1 Simple assignment 6.5.16.1 简单赋值

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;左操作数具有原子的、限定的或非限定的指针类型,并且(考虑左操作数在左值转换后将具有的类型)一个操作数是指向对象类型的指针,另一个是指向限定或未限定版本的指针void,左边指向的类型具有右边指向的类型的所有限定符;
  • 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.左操作数的类型是原子的、限定的或非限定的 _Bool,右操作数是一个指针。

In case of int* p = 0x12345678;int* p = 0x12345678;情况下int* p = 0x12345678; , the left operand is a pointer and the right is an arithmetic type. ,左操作数是指针,右操作数是算术类型。
In case of int i = p;int i = p;情况下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;至于为什么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 .有关空指针、空指针常量和 NULL 宏之间区别的更多信息


Some things of note:一些注意事项:

  • If you assign a raw address to a pointer, the pointer likely needs 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.如果将原始地址分配给指针,则该指针可能需要volatile限定,因为它指向诸如硬件寄存器或 EEPROM/闪存位置之类的东西,可以在运行时更改其内容。

  • 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):标准(C17 6.3.2.3 §5 和 §6 说):

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) 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. 68)将指针转换为整数或将整数转换为指针的映射函数旨在与执行环境的寻址结构保持一致。

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.此外,来自指针的地址可能大于适合在int ,就像大多数 64 位系统的情况一样。 Therefore it is better to use the uintptr_t from <stdint.h>因此最好使用<stdint.h>uintptr_t

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM