C语言 比较从整数转换而来的指针是UB吗?

w46czmvw  于 2023-08-03  发布在  其他
关注(0)|答案(3)|浏览(84)
#define POINTER_TO_SOMETHING ((int*)(0x80000000))
#define BAD_POINTER ((int*)(0x12345678))

int *p = some_condition ? POINTER_TO_SOMETHING + 42 : BAD_POINTER;
if (p == BAD_POINTER) { ... }

字符串
这段代码是否有任何未定义的行为或只是实现定义的行为?
如果有帮助的话--代码在内核模式下运行,管理页表和其他内容,0x 80000000加上接下来的4KB已经在页表中注册了,但我猜这些特定于硬件的信息与行为是否未定义无关,这是C语言特有的。
==EDIT==我知道如果涉及到invaild指针,比较 relationally 是UB:

6.5.8 Relational operators

shift-expression
relational-expression < shift-expression
relational-expression > shift-expression
relational-expression <= shift-expression
relational-expression >= shift-expression

When two pointers are compared, ...
In all other cases, the behavior is undefined. ...


但我发现没有这样的要求 * 平等 * 测试。
转换为uintptr_t可能会减少歧义,但这不是问题所在。

nfeuvbwi

nfeuvbwi1#

比较从整数转换而来的指针是UB吗?
是的。演员表本身会有麻烦 *1,然后比较也会有麻烦。

  • 指针相等比较 *,==!=对相同类型的有效指针和空指针有效。

@Eric Postpischil 1小时前提供了详细信息。
为了实现OP的更大目标,请考虑另一种选择:创建全局int对象,而不是(int*)(0x80000000)(int*)(0x12345678)

int pointer_test_something[42];
int pointer_test_bad;

#define POINTER_TO_SOMETHING (&pointer_test_something[0])
#define BAD_POINTER (&pointer_test_bad)

...

int *p = some_condition ? POINTER_TO_SOMETHING + 42 : BAD_POINTER;
if (p == BAD_POINTER) { ... }

字符串

  • 1整数可以转换为任何指针类型。除非前面指定,否则结果是实现定义的,可能没有正确对齐,可能没有指向引用类型的实体,并且在存储到对象中时可能产生不确定的表示形式。C23dr § 6.3.2.3 www.example.com
h5qlskok

h5qlskok2#

比较任何两个指针都是定义良好的(但可能没有意义,具体取决于系统)。未定义的行为与指针算术一起出现。
C语言中的指针运算是由加法运算符(二进制+和-)定义的。
C17 6.5.6 §8:
如果指针操作数和结果都指向同一个数组对象的元素,或者指向数组对象最后一个元素之后的元素,则计算不应产生溢出;否则,行为是未定义的。
在这种情况下,编译器不知道指针指向何处。它们不指向数组,因此这是未定义的行为。
然而,需要在数组外执行指针运算的嵌入式系统编译器几乎总是实现非标准的扩展,以保证良好定义的行为。
因为它是一个普通的整数,所以转换为uintptr_t而不是指针,然后对该类型进行所有算术运算可能更安全,更明智。
请注意,((int*)(0x80000000))几乎肯定总是一个bug。在大多数上下文中,这必须是一个volatile限定指针。查看How to access a hardware register from firmware?

ncgqoxb0

ncgqoxb03#

在代码中,您可以预期一些内容是UB:

// (1) conversion of integer to pointer is implementation-defined
#define POINTER_TO_SOMETHING ((int*)(0x80000000))
#define BAD_POINTER ((int*)(0x12345678))

// (2) addition of 42 onto pointer is only allowed when this addition
// advances the pointer within an array, otherwise UB
int *p = some_condition ? POINTER_TO_SOMETHING + 42 : BAD_POINTER;

// (3) equality comparison between pointers is never UB
if (p == BAD_POINTER) { ... }

字符串
如果不查阅编译器的手册,就不可能判断此代码是否包含UB。一般来说,从整数到指针的Map是由实现定义的。编译器可能总是将POINTER_TO_SOMETHING视为指向几乎无限大数组的指针,在这种情况下,POINTER_TO_SOMETHING + 42是安全的。否则,它可能会包含未定义的行为,因为+运算子只能在数组中前移指标。
不幸的是,尽管整数到指针的转换是实现定义的行为,并且编译器必须对实现定义的行为进行记录,GCC并没有对此做太多说明:
从整数到指针的强制转换在指针表示形式小于整数类型时丢弃最高有效位,在指针表示形式大于整数类型时根据整数类型的有符号性进行扩展,否则位不变。

案例(1)、(2)、(3)的行为定义

(1)整数到指针的转换

可以将整数转换为任何指针类型。除了前面指定的以外,结果是实现定义的,可能未正确对齐,可能未指向引用类型的实体,并且在存储到对象中时可能产生不确定的表示

  • C236.3.2.35页

(2)将整数加到指针上

[...]如果指针操作数和结果不指向同一数组对象的元素,也不指向数组对象的最后一个元素之后的元素,则该行为未定义。[...]

  • C23 6.5.6第9页

(3)指针之间的相等性比较

当且仅当两个指针都是空指针且都指向同一对象时,两个指针的比较结果相等(包括指向对象的指针和在其开始处的子对象)或函数,两者都是指向同一数组对象的最后一个元素之后的指针,或者一个是指向经过一个数组对象末尾的数组对象的指针,另一个是指向另一个数组对象的开头的指针,该数组对象正好在地址空间中的第一个数组对象之后。

  • C23 6.5.9第7页

(4)指针之间的关系比较

该规则为<=>等。与等式比较相比是不同的。如果指针不指向同一个对象或数组,则为UB。

  • C23 6.5.8第6页

相关问题