cimplementationc-standard-librarystrtoul

Passing two references to the same object in strtoul


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:


Solution

  • 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).