在 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)
(请参阅下面关于 更新 的注释。)
在 str
和 endptr
中传递对同一对象的引用是否正确?还是它没有在我脸上爆炸只是一个幸运的巧合?
stdlib
的参考手册没有提到 (for example)。
更新:
- 在评论和回答中引用了C标准。这里有一个 link 的草稿:ISO N2310.
- 在本文档中,
strtoul
函数的第一个参数称为 nptr
,与此问题中使用的名称 str
相对。下面的回答和讨论大多使用nptr
.
- 第 6.7.3.1 节包含类型限定符的正式定义
restrict
。
- 第 7.22.1.3 节包含
strtoul()
的描述
除restrict
限定符外,C 2018 7.22.1.4中strtoul
的文档和7.1.4中一般使用标准库的文档均未声明任何禁止*endptr
指向与 nptr
相同的内存(其中 endptr
和 nptr
分别是 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)
.
调用的
以下代码在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)
(请参阅下面关于 更新 的注释。)
在 str
和 endptr
中传递对同一对象的引用是否正确?还是它没有在我脸上爆炸只是一个幸运的巧合?
stdlib
的参考手册没有提到 (for example)。
更新:
- 在评论和回答中引用了C标准。这里有一个 link 的草稿:ISO N2310.
- 在本文档中,
strtoul
函数的第一个参数称为nptr
,与此问题中使用的名称str
相对。下面的回答和讨论大多使用nptr
. - 第 6.7.3.1 节包含类型限定符的正式定义
restrict
。 - 第 7.22.1.3 节包含
strtoul()
的描述
除restrict
限定符外,C 2018 7.22.1.4中strtoul
的文档和7.1.4中一般使用标准库的文档均未声明任何禁止*endptr
指向与 nptr
相同的内存(其中 endptr
和 nptr
分别是 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)
.