A few questions about legal arguments to printf(“%s”, …)

流过昼夜 提交于 2020-01-03 09:19:11

问题


I'm creating a modified printf implementation, and I'm not sure about the answers to these questions.

  1. Does zero work as a null string? (Is printf("%s", 0) allowed?)

    I'm guessing no, because 0 is an int. But then this prompts this question:

  2. Does NULL work as a null string? (Is printf("%s", NULL) allowed?)

    Logically, I think it should be yes, because NULL implies a pointer; but a lot of implementations seem to have #define NULL 0, so I feel in practice it might be no. Which is correct?

  3. Does the pointer type have to point to char? (Is printf("%s", (void const *)"") allowed?)

    My guess is that the type doesn't matter, but I'm not sure.


回答1:


Case 1 is undefined behavior because the type of the argument (int) does not match the type required by the format specifier (char *).

Case 2 is undefined behavior for the same reason. NULL is allowed to be defined as any integer constant expression with value 0, or such an expression cast to (void *). None of these types are char *, so the behavior is undefined.

Case 3 is undefined behavior for the same reason. "" yields a valid pointer to a null-terminated character array (string), but when you cast it to const void *, it no longer has the right type to match the format string. Thus the behavior is undefined.




回答2:


I believe it would compile just fine but behavior is undefined.

Something about how printf works and why it is considered to be unsafe. printf takes as many arguments, as you give it with only one (first one) being required. All the arguments (except for the first one - the pattern) are then treated as an array of bytes. It doesn't check types or anything. It simply prints.

Printing string is more complicated as it just goes on until it finds 0 byte ('\0'). To clarify, you can try testing it with integers. As you know, short is 2 bytes-long, long is 4 and long long is 8. If you told printf to print long and passed 2 shorts - it would treat them as one long. Or if you passed long long and told it to print long, it would take 4 first bytes and use them for printing.

With that in my these specific cases would probably (didn't test) print nothing but it is considered to be undefined behavior. If these values weren't 0s, it may print some characters if you passed some specific values which had a couple non-'\0's at the beginning.

Not quite sure if it helps but hope so.




回答3:


From the online C11 draft:

7.21.6.1 The fprintf function

...
s If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type.280) Characters from the array are written up to (but not including) the terminating null character. If the precision is specified, no more than that many bytes are written. If the precision is not specified or is greater than the size of the array, the array shall contain a null character.
280) No special provisions are made for multibyte characters.

Anything other than a pointer to the first element of an array of char containing at least 1 character (the 0 terminator) invokes undefined behavior.

If you're building your own implementation, you can certainly define your own behavior for 0 or NULL.

Oh, and as far as the definition of NULL is concerned:

6.3.2.3 Pointers

...
3 An integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant.66) If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer, is guaranteed to compare unequal to a pointer to any object or function.
66) The macro NULL is defined in <stddef.h> (and other headers) as a null pointer constant; see 7.19

Basically, any 0-valued integer expression in a pointer context is considered a NULL pointer.



来源:https://stackoverflow.com/questions/12222447/a-few-questions-about-legal-arguments-to-printfs

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!