Your third example:
printf("%s",(char *){'H','i','\0'});
isn't even legal (strictly speaking it's a *constraint violation*), and you should have gotten at least one warning when compiling it. When I compiled it with gcc with default options, I got 6 warnings:
c.c:3:5: warning: initialization makes pointer from integer without a cast [enabled by default]
c.c:3:5: warning: (near initialization for ‘(anonymous)’) [enabled by default]
c.c:3:5: warning: excess elements in scalar initializer [enabled by default]
c.c:3:5: warning: (near initialization for ‘(anonymous)’) [enabled by default]
c.c:3:5: warning: excess elements in scalar initializer [enabled by default]
c.c:3:5: warning: (near initialization for ‘(anonymous)’) [enabled by default]
The second argument to `printf` is a *compound literal*. It's legal (but odd) to have a compound literal of type `char*`, but in this case the *initializer-list* portion of the compound literal is invalid.
After printing the warnings, what gcc seems to be doing is (a) converting the expression `'H'`, which is of type `int`, to `char*`, yielding a garbage pointer value, and (b) ignoring the remainder of the initializer elements, `'i'` and `'\0'`. The result is a `char*` pointer value that points to the (probably virtual) address `0x48` -- assuming an ASCII-based character set.
Ignoring excess initializers is valid (but worthy of a warning), but there is no implicit conversion from `int` to `char*` (apart from the special case of a null pointer constant, which doesn't apply here). gcc has done its job by issuing a warning, but it could (and IMHO should) have rejected it with a fatal error message. It will do so with the `-pedantic-errors` option.
If your compiler warned you about those lines, you should have included those warnings in your question. If it didn't, either crank up the warning level or get a better compiler.
Going into more detail about what happens in each of the three cases:
printf("%s","Hi");
A C string literal like `"%s"` or `"Hi"` creates an anonymous statically allocated array of `char`. (This object is not `const`, but attempting to modify it has undefined behavior; this isn't ideal, but there are historical reasons for it.) A terminating `'\0'` null character is added to make it a valid string.
An expression of array type, in most contexts (the exceptions are when it's the operand of the unary `sizeof` or `&` operator, or when it's a string literal in an initializer used to initialize an array object) is implicitly converted to ("decays to") a pointer to the array's first element. So the two arguments passed to `printf` are of type `char*`; `printf` uses those pointers to traverse the respective arrays.
printf("%s",(char[]){'H','i','\0'});
This uses a feature that was added to the language by C99 (the 1999 edition of the ISO C standard), called a *compound literal*. It's similar to a string literal, in that it creates an anonymous object and refers to the value of that object. A compound literal has the form:
( type-name ) { initializer-list }
and the object has the specified type and is initialized to the value given by the initializer list.
The above is nearly equivalent to:
char anon[] = {'H', 'i', '\0'};
printf("%s", anon);
Again, the second argument to `printf` refers to an array object, and it "decays" to a pointer to the array's first element; `printf` uses that pointer to traverse the array.
Finally, this:
printf("%s",(char*){'A','B','\0'});
as you say, fails big time. The type of a compound literal is usually an array or structure (or union); it actually hadn't occurred to me that it could be a scalar type such as a pointer. The above is nearly equivalent to:
char *anon = {'A', 'B', '\0'};
printf("%s", anon);
Obviously `anon` is of type `char*`, which is what `printf` expects for a `"%s"` format. But what's the initial value?
The standard requires the initializer for a scalar object to be a single expression, optionally enclosed in curly braces. But for some reason, that requirement is under "Semantics", so violating it is not a constraint violation; it's merely undefined behavior. That means the compiler can do anything it likes, and may or may not issue a diagnostic. The authors of gcc apparently decided to issue a warning and ignore all but the first initializer in the list.
After that, it becomes equivalent to:
char *anon = 'A';
printf("%s", anon);
The constant `'A'` is of type `int` (for historical reasons, it's `int` rather than `char`, but the same argument would apply either way). There is no implicit conversion from `int` to `char*`, and in fact the above initializer is a constraint violation. That means a compiler *must* issue a diagnostic (gcc does), and *may* reject the program (gcc doesn't unless you use `-pedantic-errors`). Once the diagnostic is issued, the compiler can do whatever it likes; the behavior is undefined (there's some language-lawyerly disagreement on that point, but it doesn't really matter). gcc chooses to *convert* the value of `A` from `int` to `char*` (probably for historical reasons, going back to when C was even less strongly typed than it is today), resulting in a *garbage* pointer with a representation that probably looks like `0x00000041` or 0x0000000000000041`.
That garbage pointer is then passed to `printf`, which tries to use it to access a string at that location in memory. Hilarity ensues.
There are two important things to keep in mind:
1. If your compiler prints warnings, pay close attention to them. gcc in particular issues warnings for many things that IMHO should be fatal errors. *Never* ignore warnings unless you understand what the warning means, thoroughly enough for your knowledge to override that of the authors of the compiler.
2. Arrays and pointers are very different things. Several rules of the C language seemingly conspire to make it look like they're the same. You can *temporarily* get away with assuming that arrays are nothing more than pointers in disguise, but that assumption will eventually come back to bite you. Read section 6 of the [comp.lang.c FAQ](
[To see links please register here]
); it explains the relationship between arrays and pointers better than I can.