在 strtoul 中传递对同一对象的两个引用

Passing two references to the same object in strtoul

以下代码在gcc 11.2.1下运行良好:

// test.c
#include<stdio.h>
#include<stdlib.h>

int main(int argc, char **argv){
    char *msg;
    unsigned int val;

    msg = "1024 2048 4096 13";
    while(*msg != '[=10=]'){
        val = strtoul(msg, &msg, 10);
        printf("%u\n",val);
    }
    return 0;
}

gcc -Wall -o test.bin test.c
$ ./test.bin
1024
2048
4096
13

关于函数 strtoul,

unsigned long int strtoul(const char *str, char **endptr, int base)

(请参阅下面关于 更新 的注释。)

strendptr 中传递对同一对象的引用是否正确?还是它没有在我脸上爆炸只是一个幸运的巧合?

stdlib 的参考手册没有提到 (for example)。

更新:

restrict限定符外,C 2018 7.22.1.4中strtoul的文档和7.1.4中一般使用标准库的文档均未声明任何禁止*endptr 指向与 nptr 相同的内存(其中 endptrnptr 分别是 strtoul 的第二个和第一个参数),它们也不说明在此条件下对规范的任何放宽(例如,没有断言如果这种条件成立,行为将是未定义的)。

所以我们只需要考虑 restrict 限定符。 strtoul 声明为 unsigned long int strtoul(const char * restrict nptr, char ** restrict endptr, int base)。使用 6.7.3.1 中 restrict 的正式定义并首先考虑 nptr 上的 restrict,6.7.3.1 4 告诉我们,如果 nptr 或any 以任何方式修改,则用于访问它的每个其他左值都应基于 nptr。满足这个条件是因为strtoul不会修改nptr指向的字符串。

考虑到 endptr 上的 restrict,我们观察到它指向的内存确实被修改了,因为 strtoul 向该内存存储了一个值。然后 6.7.3.1 4 要求用于访问该内存的每个其他左值应基于 endptr。此条件得到满足是因为 strtoul 除了通过 endptr.

之外不访问表示 msg 的字节

因此,例程应该按照 7.22.1.4 中指定的方式运行,即使它是用 strtoul(msg, &msg, 10).

调用的