通过严格解释C标准允许对可能无效的指针进行操作
原始问题
(请参阅“编辑:更新的方案”)
这个问题可能是一个或另一个方面的重复,涉及到超出范围的对象的指针的未定义行为的大量问题。但我在这里找到的所有问题主要是专门的用例。 所以我想把这个问题颠倒过来,不要问是否禁止某些事情,但是究竟允许什么?
有一个可能的场景:你有一个带有指针的函数 – 你不知道它是否来自一个(仍然)有效的对象。 在所有情况下哪些操作不是未定义的行为? 哪个可能有未指定的副作用?
int * myFunc(const int * const A, int * B) { ... }
编辑:更新的方案
在对问题的评论和Matt McNabbs的回答中 ,有人指出UB最有可能上升,因为在调用场景中的函数期间使用了无效指针(s值)。 因此,我会稍微改变一下场景(按照Keith Thompsons回答的例子):
int *ptr = malloc(sizeof *ptr); /* the value of ptr is now valid, possibly NULL */ if (ptr != NULL) { /* the value of ptr is valid and non-null */ free(ptr); /* the value of ptr is now invalid */ ... /* here operations in question */ }
允许的操作列表:
(由您的答案和评论填写并更正。)
- 定义明确:获取指针变量的大小。 例如
sizeof(ptr)
- 定义明确:取去引用指针的大小(假设它不是
void *
)。 例如sizeof(*ptr)
(参见EOF和Jonathan Leffler的评论)。 - 定义良好:为指针赋予另一个(有效)值(而不是引用变量!)。 例如
ptr = NULL;
-
定义明确:访问Pointer的表示(例子来自Keith Thompson的回答 ):
unsigned char rep[sizeof ptr]; memcpy(rep, &ptr, sizeof ptr); /* ok, accesses the representation */ /* but not the value */
根据标准未明确定义的操作:
(由您的答案和评论填写并更正。)
这些操作通常被视为在无效指针上定义良好,但根据标准没有明确定义:
- 未定义:比较指针的值(甚至是NULL指针常量)
- 未定义:转换为整数值
与所有未定义的行为一样,你可以使用许多机器上的指针来逃避(ab),但是C标准并不保证你会逃脱并且有(或曾经是)机器滥用指针会导致程序失败。
一般来说,请参阅Keith Thompson的答案 – 以及下面的广泛评论。
使用无效指针值具有未定义的行为。
int *ptr = malloc(sizeof *ptr); // the value of ptr is now valid, possibly NULL if (ptr != NULL) { // the value of ptr is valid and non-null free(ptr); // the value of ptr is now invalid ptr; // UNDEFINED BEHAVIOR }
引用: N1570 6.2.4p2:
当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针的值变得不确定。
编译器可能不会为表达式语句ptr;
生成任何代码ptr;
; 当然,这是在未定义行为的范围内。
对指针对象的任何不检索其值的操作(至少可能)定义得很好:
sizeof ptr; // ok, doesn't use the value sizeof *ptr; // ok, doesn't use the value, only the type ptr = NULL; // ok
您还可以访问指针对象的表示forms而无需访问其值:
unsigned char rep[sizeof ptr]; memcpy(rep, &ptr, sizeof ptr); // ok, accesses the representation // but not the value
虽然结果不是很多。
这个问题非常广泛。 但要回答您的具体情况:
int * myFunc(const int * const A, int * B)
如果使用无效指针值调用此函数,则通过在准备调用函数时评估无效指针值, 已经导致了未定义的行为 。
所有的“明确定义”的要点都没有明确定义,因为一旦发生UB,猫就无法放回袋中。