The following code runs well under 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 != '\0'){
val = strtoul(msg, &msg, 10);
printf("%u\n",val);
}
return 0;
}
gcc -Wall -o test.bin test.c
$ ./test.bin
1024
2048
4096
13
Regarding the function strtoul
,
unsigned long int strtoul(const char *str, char **endptr, int base)
(See notes on Update below.)
Is it correct to pass references to the same object in str
and endptr
? Or is it just a lucky coincidence that it did not explode in my face?
The reference manuals to stdlib
do not mention that (for example).
Update:
- In the comments and answer it is referenced the C standard. Here a link to its draft: ISO N2310.
- In this document, the first argument of the
strtoul
function is callednptr
as opposed tostr
which is the name used in this question. The answer and discussion below mostly usesnptr
. - Section 6.7.3.1 contains the formal definition of the type qualifier
restrict
. - Section 7.22.1.3 contains the description of
strtoul()
CodePudding user response:
Other than the restrict
qualifiers, neither the documentation for strtoul
, in C 2018 7.22.1.4, nor the documentation for using the standard library generally, in 7.1.4, state any prohibition on *endptr
pointing to the same memory that nptr
does (where endptr
and nptr
are the second and first arguments of strtoul
, respectively), nor do they state any relaxation of the specification under this condition (for example, there is no assertion that the behavior would be undefined if such a condition holds).
So we just need to consider the restrict
qualifiers. strtoul
is declared as unsigned long int strtoul(const char * restrict nptr, char ** restrict endptr, int base)
. Using the formal definition of restrict
in 6.7.3.1 and considering the restrict
on nptr
first, 6.7.3.1 4 tells us that, if the memory pointed to by nptr
or any is modified by any means, then every other lvalue used to access it shall be based on nptr
. This condition is satisfied because strtoul
will not modify the string that nptr
points to.
Considering the restrict
on endptr
, we observe the memory it points to is indeed modified, as strtoul
stores a value to that memory. Then 6.7.3.1 4 requires that every other lvalue used to access that memory shall be based on endptr
. This condition is satisfied because strtoul
does not access the bytes representing msg
other than through endptr
.
Therefore, the routine should function as specified in 7.22.1.4 even if it is called with strtoul(msg, &msg, 10)
.