Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C: why printing a null char with %s prints "(null)"?

Tags:

c

gcc

Why does printing a null char ('\0', 0) with %s prints the "(null)" string actually?

Like this code:

char null_byte = '\0';
printf("null_byte: %s\n", null_byte);

...printing:

null_byte: (null)

...and it even runs without errors under Valgrind, all I get is the compiler warning warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat] (note: I'm using gcc 4.6.3 on 32bit Ubuntu)

like image 913
NeuronQ Avatar asked Dec 03 '12 10:12

NeuronQ


People also ask

Can you print a null character in C?

No, it is not possible to do this without modifying printf(). The null character is only used to signify the end of a string, and should not be printed. More than one call to printf() can contribute to the same 'formatted line'.

What happens if you print null in C?

The NULL pointer doesn't point to any address, and attempting to print it causes undefined behavior. Undefined meaning it's up to your compiler or C library to decide what to do when it tries to print NULL.

Why null is printed?

It's just the string and the character array parameters that cause ambiguity as character arrays and objects can happily coexist. The char array null cannot be printed by the PrintStream since it causes a NullPointerException .

Does printf stop at null character?

No , printf does not do that in any case .


3 Answers

It's undefined behavior, but it happens that on your implementation:

  • the int value of 0 that you pass is read by %s as a null pointer
  • the handling of %s by printf has special-case code to identify a null pointer and print (null).

Neither of those is required by the standard. The part that is required[*], is that a char used in varargs is passed as an int.

[*] Well, it's required given that on your implementation all values of char can be represented as int. If you were on some funny implementation where char is unsigned and the same width as int, it would be passed as unsigned int. I think that funny implementation would conform to the standard.

like image 106
Steve Jessop Avatar answered Oct 18 '22 00:10

Steve Jessop


Well, for starters, you're doing it wrong. '\0' is a character and should be printed with %c and not %s. I don't know if this is intentional for experimentation purposes.

The actual binary value of \0 is, well, 0. You're trying to cast the value 0 to a char * pointer, which would result in an invalid reference and crash. Your compiler is preventing that with a special treatment of the %s value.

Valgrind won't catch it because it runs on the resulting binary, not the source code (you'd need a static analyzer instead). Since the compiler has already converted that call into a safe "null pointer" text, valgrind won't see anything amiss.

like image 4
Mahmoud Al-Qudsi Avatar answered Oct 18 '22 00:10

Mahmoud Al-Qudsi


null_byte contains 0. When you use %s in printf, you are trying to print a string, which is an adress of a char (a char *). What you do in your code, is that you are passing the adress 0 (NULL) as the adress of your string, which is why the output is null. The compiler warned you that you passed the wrong type to the %s modifier. try printf("null_byte: %s\n", &null_byte);

like image 1
Waterfrag Avatar answered Oct 18 '22 01:10

Waterfrag