通过严格解释C标准允许对可能无效的指针进行操作

Mar*_* A. 1 c pointers c89 undefined-behavior

原始问题

(请参阅"编辑:更新的方案")

这个问题可能是一个或另一个方面的重复,涉及到超出范围的对象指针的未定义行为的大量问题.但我在这里找到的所有问题主要是专门的用例.所以我想把这个问题颠倒过来,不要问是否禁止某些事情,但是究竟允许什么?

有一个可能的场景:你有一个带有指针的函数 - 你不知道它是否来自一个(仍然)有效的对象.在所有情况下哪些操作不是未定义的行为?哪个可能有未指定的副作用?

int * myFunc(const int * const A, int * B)
{
   ...
}
Run Code Online (Sandbox Code Playgroud)

编辑:更新的方案

在对问题的评论和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 */
}
Run Code Online (Sandbox Code Playgroud)

允许的操作列表:

(由您的答案和评论填写并更正.)

  • 定义明确:获取指针变量的大小.例如sizeof(ptr)
  • 定义明确:取去引用指针的大小(假设不是void *).例如sizeof(*ptr)(见EOFJonathan Leffler的评论).
  • 定义良好:将另一个(有效)值赋给指针(而不是引用变量!).例如ptr = NULL;
  • 定义明确:访问指针的表示(来自Keith Thompson回答):

    unsigned char rep[sizeof ptr];
    memcpy(rep, &ptr, sizeof ptr); /* ok, accesses the representation */
                                   /* but not the value */
    
    Run Code Online (Sandbox Code Playgroud)

根据标准未明确定义的操作:

(由您的答案和评论填写并更正.)

这些操作通常被视为在无效指针上定义良好,但根据标准没有明确定义:

  • 未定义:比较指针的值(甚至是NULL指针常量)
  • 未定义:转换为整数值

与所有未定义的行为一样,你可以使用许多机器上的指针来逃避(ab),但是C标准并不能保证你会逃脱,而且有(或曾经是)机器滥用指针会导致程序失败.

一般来说,请参阅Keith Thompson的答案 - 以及下面的广泛评论.

Kei*_*son 5

使用无效指针具有未定义的行为.

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
}
Run Code Online (Sandbox Code Playgroud)

引用:N1570 6.2.4p2:

当指针指向(或刚刚过去)的对象到达其生命周期的末尾时,指针的值变得不确定.

编译器可能不会为表达式语句生成任何代码ptr;; 当然,这是在未定义行为的范围内.

对指针对象的任何不检索其值的操作(至少可能)定义良好:

sizeof ptr;  // ok, doesn't use the value
sizeof *ptr; // ok, doesn't use the value, only the type
ptr = NULL;  // ok
Run Code Online (Sandbox Code Playgroud)

您还可以访问指针对象的表示形式而无需访问其值:

unsigned char rep[sizeof ptr];
memcpy(rep, &ptr, sizeof ptr); // ok, accesses the representation
                               // but not the value
Run Code Online (Sandbox Code Playgroud)

虽然你对结果的影响不大.

  • 即使代码可以访问指针的表示,也不能保证由此获得的字节可以用于任何有用的目的.给定`char*p,*q; P =释放calloc(1,1); 自由(P); q = calloc(1,1);`我想,它会合法地用于`if(!memcmp(&p,&q,sizeof p))(*p)++;`发射核导弹,因为`p`是非法的,`q`可以合法地具有相同的表示,并且观察到`p`和`q`具有相同的按位表示的行为将不会使`p`有效. (2认同)