我已经code in Code Reveiw按预期“工作”,但可能已经UB
.
代码有一个大小相同的char
数组,称为GP2_format[]
。为了检测指针format
是否与其中一个元素GP2_format[][0]
的地址具有相同的值,下面的代码简单地测试指针是否>=
是最小的元素而<=
是最大的元素。由于元素的大小为1,不需要进一步检查。
const char GP2_format[GP2_format_N + 1][1];
const char *format = ...;
if (format >= GP2_format[0] && format <= GP2_format[GP2_format_N]) Inside()
else Outside();
C11§6.5.8/5关系运算符
< > <= >=
似乎将此定义为比较数组外部指针时可怕的未定义行为。比较两个指针时,结果取决于所指向对象的地址空间中的相对位置。如果指向对象类型的两个指针都指向
相同的对象。。。对于同一个数组对象,它们比较相等。…(相同的对象确定)。。。。(同一工会确定)。。。。(相同的数组确定)。。。在所有其他情况下,行为都是未定义的。
Q1代码指针是否在UB中比较?
如果是,那么什么是定义良好的备选方案,搜索O(1)到可疑的
GP2_get_type()
?较慢的解决方案
代码可以对每个
GP2_get_type()
依次测试format
,或者将值转换为GP2_format[]
,排序一次并执行O(ln2(n))搜索。类似
...if a pointer is part of a set,但这个“集合”不是随机的,它是一个数组。
intptr_t
approach-也许是UB。#include <stdio.h>
typedef enum {
GP2_set_precision,
GP2_set_w,
GP2_setios_flags_,
GP2_string_,
GP2_unknown_,
GP2_format_N
} GP2_type;
const char GP2_format[GP2_format_N + 1][1];
static int GP2_get_type(const char *format) {
// candidate UB with pointer compare
if (format >= GP2_format[0] && format <= GP2_format[GP2_format_N]) {
return (int) (format - GP2_format[0]);
}
return GP2_format_N;
}
int main(void) {
printf("%d\n", GP2_get_type(GP2_format[1]));
printf("%d\n", GP2_get_type("Hello World")); // potential UB
return 0;
}
输出(如预期,但可能是UB)
1
5
最佳答案
如果您想遵守C标准,您可以选择:
对目标范围内的每个指针执行单独的==
或!=
测试
如果是一个非常大的集合,可以使用哈希表或搜索树之类的东西来加速这个过程
重新设计代码以不需要此检查。
“可能有效”的方法是将所有值强制转换为uintptr_t
,然后进行关系比较。如果系统有一个具有绝对顺序的内存模型,那么它应该定义uintptr_t
并保留该顺序;如果它没有这样的模型,那么关系比较的思想无论如何都不会起作用。