It is impossible to understand this code from CodeGolf

So, I lost my weekend on StackOverflow and saw this issue on Hot Network Questions .

Background

Hello golfers! I would like to learn all programming languages! But I have a short attention span ... and copying everything Hello World examples are getting boring ... but I love fire! ^ W ^

Call

So here's the plan! I want you all to write the smallest code that will compile, print Goodbye Cruel World !, and then crash. Or, as a bonus twist challenge, print Hello World! and crashing with Goodbye Cruel World!

As a student wanting to fully understand the C language, I was very confused when I came across the C answer to this call:

main(){puts(puts("Goodbye Cruel World!"));}

      

Prints out a string and then tries to use the return value as a pointer to another string to print, which causes a segmentation fault.

Thanks to the puts()

documentation, I found that it puts()

returns a non-negative value on success. So if I understood correctly, this is equivalent to something like:

puts(2); 

      

How 2

is "a pointer to another printable string"

Later, an improvement was added to this same answer:

main(i){i=puts("Goodbye Cruel World!")/0;}

      

And this time I was completely lost. Therefore it i

is taken as the main argument used to store the return value puts()

. OK. But what about \0

? Why use a symbol NUL-TERMINATOR

?

If you could light me up a little, I would be very interested to understand this. Also, I think the title of the question might be a little more accurate to rephrase, but I couldn't put my misunderstanding into words.

+3


source to share


3 answers


Both solutions cause undefined behavior.

First solution:

main(){puts(puts("Goodbye Cruel World!"));}

      

evaluates puts("Goodbye Cruel World!")

, which returns a non-negative value on success. This value is passed to puts()

. Now, according to ยง6.5.2.2 7 :

If the expression denoting the called function is of a type that includes the prototype, the arguments are implicitly converted, as if by assignment , to the types of the corresponding parameters, assuming the type of each parameter is an unqualified version of its declared type.



Thus, the code tries to convert the value returned from the first call to puts()

, as if it had been assigned, a value of the type char *

. This is the type of the left operand in the assignment, and the type of the right operand is int

. The left operand is a pointer type, so the right operand must be a pointer to a qualified or unqualified version of a compatible type, a pointer to, void

or a null pointer constant ( ยง6.5.16.1 1 ). None of them are true, so this is a constraint violation and the compiler should issue a warning.

This behavior is undefined in the sense that there is no specific behavior to run this code.

The second solution is undefined behavior too, since division by zero results in undefined behavior ( ยง6.5.5 5 )

The result of the / operator is the quotient of the first operand division by the second; the result of the% operator is the remainder. In both operations, if the value of the second operand is 0, the behavior is undefined.

Undefined behavior may or may not include your program "crashing".

+2


source


And to answer your second question:

main(i){i=puts("Goodbye Cruel World!")/0;}

      



There is a difference between '\0'

and /0

The first is a character NUL

and the second is division by zero. So this code is trying to divide the result puts

by zero.

+3


source


The code doesn't work because the type of the argument puts()

is equal const char *

, which means "pointer to read only char

".

This is static, it doesn't change just because you are trying to pass something else to it, instead the function interprets the value of the argument as if it were a pointer to a character (assuming the compiler even managed to compile it, which is a hard guess here. since the return value is int

not converted to const char *

).

In general, small integers such as 2

are not valid as pointers on desktop / server class systems (and not all built-in ones), i.e. for a typical process, there is no memory at this address, so it often happens that the operating system stops the process of violating its boundaries. But, as mentioned in the comments, this part is undefined.

+2


source







All Articles