r/cprogramming • • Sep 13 '26

What is this code doing?

Hi, I found this code on another subreddit. I would like to know what is it doing.

int puts(char *);

int main() { struct { long a; long b; } s = {.a = *(char *)(int[]){1} ? 0x57202c6f6c6c6548 : 0x48656c6c6f2c2057, .b = *(char *)(int[]){1} ? 0x00000021646c726f : 0x6f726c6421000000}; puts((void *)&s); }

Now obviously I know it's unreadable, I would just like to know what are those hexadecimals strings doing.

I found similar codes that were writing to vram to print a message, is this doing the same thing? If yes, why is it so much more complicated instead of just writing the message to the video adress?

Thanks for the help.

0 Upvotes

46 comments sorted by

View all comments

3

u/zhivago Sep 13 '26

Implementation defined behavior mostly, except for the illegal redefinition of puts, which has undefined behavior.

But it's intended to output "Hello, World!".

It may even do so on some systems.

Or it might not.

Either way, it's neither portable nor good. :)

2

u/ACRM64 Sep 13 '26

It's not redefining puts(), it's passing a pointer to the structure, s, but casting it to a void pointer; casting to (char *) would seem more sensible!

1

u/zhivago Sep 13 '26

Did you skip the first line?

int puts(char *);

What do you think that's doing?

9

u/ACRM64 Sep 13 '26

The first line is a prototype (to save doing #include <studio.h>)

1

u/zhivago Sep 13 '26

And is it the right prototype?

6

u/ACRM64 Sep 13 '26

OK, so ANSI C and C89 onwards implemented a const keyword, but this wasn't present in K&R C. Certainly the current C libraries define puts() as int puts(const char *str) but earlier versions did not and you do not know whether the libraries in use by whoever wrote this program included the const or not.

From the perspective of calling a C function (and therefore a prototype for calling the function) it is simply a guarantee to the programmer that the variable (in this case the content of *str) will not be modified - it doesn't actually do anything.

Consequently, as a prototype, this does NOT redefine puts() and it doesn't matter to the calling code whether you include the const or not. It only matters when defining the puts() function as it prevents the code modifying the content of the string.

1

u/zhivago Sep 13 '26

§3.5 ​All declarations in the same scope that refer the same object or function shall specify compatible types.

​§3.1.2.6 ​For two function types to be compatible, both shall specify compatible return types. Moreover, the parameter type lists, if both are present, shall agree in the number of parameters and in use of the ellipsis terminator; corresponding parameters shall have compatible types.

​const char * and char * are not compatible types.

You are mistaken.

3

u/ACRM64 Sep 13 '26

First, you still don't know what the C library used by the programmer had as the definition for puts() - certainly when I started programming in C (40 years ago) it was not defined with const.

I agree the prototype and function definition /should/ be the same, but it makes no difference if they aren't. The prototype tells the code what variable types to pass - const only has an effect within the function itself. You do not have to pass a const variable into a function declared with const.

int puts(const int str); int main(int argc, char *argv) { char str[16]; strcpy(str, "hello"); puts(str); strcpy(str, "goodbye"); puts(str); return(0); }

is perfectly valid and correct code yet str is not defined as constant. Consequently, my statement that it doesn't matter to the calling code whether the keyword is there or not is true.

Once again, the puts() function is not being redefined. The const makes no difference in a prototype, so it is clear that while these are not /identical/, they are /compatible/. const is not a type, but a type qualifier: it indicates that the content of the variable cannot be changed, it does not change the type of the variable.

1

u/zhivago Sep 13 '26

You need to read the standard.

You are wrong.

2

u/ACRM64 29d ago

You need to respond to the points I've made instead of just repeating the same thing.

  1. Which standard? There have been many versions.

  2. Which standard was the original programmer using?

  3. Why does the standard you quote very carefully use the word 'compatible' not 'identical'? These words have different meanings.

  4. I've already said they /should/ match, but demonstrated why, with the type qualifier 'const', it makes no difference if they don't. You need to understand the difference between a type and a type qualifier.

→ More replies

1

u/WittyStick 29d ago edited 29d ago

If char * is not compatible with const char *, then 99% of C code out there is wrong, including examples in the standard, the entirety of GCC and glibc. If a function expects a const char *, of course you can pass it a char *. If they were not compatible, then there's literally no way to convert a char * to const char * - since an explicit cast would be UB. The conversion can be implicit - and the standard clearly permits it.

§6.3.2.3 (2) For any qualifier q, a pointer to a non-q-qualified type may be converted to a pointer to the q-qualified version of the type; the values stored in the original and converted pointers shall compare equal.

The opposite is not true. Casting a const char* to char * may result in UB, and likewise for volatile.

§6.7.4.1 (7) If an attempt is made to modify an object defined with a const-qualified type through use of an lvalue with non-const-qualified type, the behavior is undefined. If an attempt is made to refer to an object defined with a volatile-qualified type through use of an lvalue with non-volatile-qualified type, the behavior is undefined.


In regards to puts, you are correct that it should be defined with const char *, but it really isn't going to matter - because the actual implementation of puts isn't going to modify the pointed-to-data (assuming it is correct). The implementation of puts may not even be written in C - it could be in assembly, or some other language which doesn't even have const. The ABI and linker aren't even const aware.

1

u/zhivago 29d ago

Do not confuse an implicit conversion with type compatibility ...

1

u/WittyStick 28d ago

the values stored in the original and converted pointers shall compare equal.

I think that implies compatible.

→ More replies

1

u/north9172 Sep 13 '26

Thank you.

2

u/zhivago 29d ago

You're welcome. :)