📜 ⬆️ ⬇️

The test of knowledge of the C language, found in April Fool's joke

It is April 1st. Often, April Fools' jokes posted on the Internet continue their march, and float completely at unexpected times. About such a joke about the C language and this article will be. In every joke there is only a share of jokes. I adopted the code from it for a quick test of knowledge of the C language.

It is necessary to write a program (with explanations) in which the following line will work:

for(;P("\n"),R--;P("|"))for(e=C;e--;P("_"+(*u++/8)%2))P("| "+(*u/4)%2); 

Only one line, but it is possible to determine the depth of human understanding of the C language. This line will also work in C ++. I advise you to try your hand. It will not be funny. It may be useful.

At the dawn of his programming career, a friend showed me an article about the fact that the C language and UNIX is an April Fool's joke. As evidence of the absurdity of the language, the above line of code was cited. In my opinion, quite working. After some time during the interview I remembered this joke. As with many other tests, the result is not the result (it sets the goal of the work), but the process of analysis and understanding.
')
Where we took the article I do not remember. Every time I find him in a search engine for the phrase "Si and unix April Fool's joke" ( for example, here ). In these reposts, one minus in the increment after “R” and “e” was once lost, and the second backslash appeared in the "\ n" line.

Try to deal with the task yourself. Do not think about the meaning of the program.

Formatting works wonders
I strongly advise you to bring this one-line disgrace in a readable form, placing line breaks, indents and spaces.

 for ( ; P("\n"), R--; P("|")) for (e = C; e--; P("_" + (*u++ / 8) % 2)) P("| " + (*u / 4) % 2); 

This is quite easy if you have seen the text of normal programs. You can close your eyes to spaces, but the cycles should be on different lines with different indents.

You need to write an elementary program, such as "Hello world!"
Instead of displaying greetings to the whole world, you need to insert the text of the task itself and declare certain variables (this will be further).

 #include <stdio.h> int main() { ... for ( ; P("\n"), R--; P("|")) for (e = C; e--; P("_" + (*u++ / 8) % 2)) P("| " + (*u / 4) % 2); return 0; } 

This can already be discussed. Why do I need include? And is he needed here? Is it possible without return? And quite a cruel question. What are the parameters of the main function?

Do not be lazy, and try to answer these questions yourself.

Parse external loop
If a person has successfully reached this stage, then he already understands that there are two nested loops. We analyze the external.

 for ( ; P("\n"), R--; P("|")) 

Here we meet a very simple problem. There is no initializer (a semicolon immediately follows the open parenthesis). Some are confused. This is often the case if a person writes programs in another language, for example, in Pascal.

A real stumbling block, even for sufficiently experienced programmers, meets the expression "P (" \ n "), R--". Many simply do not know that there is such a “comma” operation, and that the result of his work will be the result of the expression after the comma. The expression to the comma is also calculated, but its result is not used. Moreover, this operation has the lowest priority . Therefore, P ("\ n") is executed first, and then R--.

The result of the expression R-- here is the condition of execution. This also confuses some, although this technique is often used. Many programmers find it unnecessary to write in if statements, if (a! = 0) expressions ... There is a similar case (R--! = 0). It is time to add the declaration of the first variable. The increment says that this is definitely not a real number. Any integer type, even unsigned, will do. This variable must not only be declared, but also initialized with some positive value (preferably small).

Usually, having reached here, it is already clear to everyone that there is a function P that accepts a string as input. There are no problems here. It is necessary to declare this function. Since the meaning is not important to us, it may even be empty. I prefer the function that displays the text on the screen (here it was useful in advance written in #include <stdio.h>). I believe that a programmer of any level should be able to write this function.

Analysis of the internal cycle
  for (e = C; e--; P("_" + (*u++ / 8) % 2) ) 

Here in the cycle, everything is already familiar. Decrement in the check on the execution of the cycle, as it was above. We add the variable e, by analogy with R. You can immediately declare a variable C of the same type, although it can be a constant, or even define. Here is the author's will.

Interest here is a call to the function P.

  P("_" + (*u++ / 8) % 2) 

If we look further, we will see a similar construction in the function body.

  P("| " + (*u / 4) % 2); 

Here it is necessary to have patience. The goal is close. This is the crown of this "masterpiece". Do not rush to open the following explanation, think.

Highlight
Parse two expressions:

 "_" + (*u++ / 8) % 2 

 "| " + (*u / 4) % 2 

Further we will consider the first expression. It is more complicated. It is clear that here the expression in brackets is first calculated, then the remainder from division by 2 is taken from it, at the end this number is added to the string.

The simplest is the calculation of the remainder of the division. Occasionally there are programmers who do not use such an operation. They may be embarrassed. The main thing is that this operation is performed on integer types and the result is also integer. An insidious question for self-study, can the result of the expression (* u ++ / 8)% 2 be negative?

Since the result of the expression in parentheses must be integer, then the division operation is integer, and the dividend is integer. For novice programmers, the expression * u ++ can cause uncertainty: in the presence of post-increment in the expression and in the priority of executing post-increment operations and pointer dereference. This technique is sometimes used in C programs when moving along an array. The expression returns the value at the current pointer (before incrementing) and shifts the pointer to the next element. Therefore, the variable u is not just a pointer, but is also an array. An additional question, what size (in the elements) should this array be?

The most "beautiful" technique is adding a number to a string. We must remember that this is C language. You should not wait for the conversion of a number into a string, and even more so the lines into a number. Everything is much more strange than it may seem at first glance, but very logical for C. A string is an array of characters, which means a pointer to the memory where the first character is located. If this is a pointer, then adding an integer to it means calculating an address that is shifted relative to the original pointer by a specified number of elements. In this example, after obtaining the remainder of division by 2, either 0 or 1. is output. Accordingly, the string is passed to the P function without offset (as it is), or shifted by one character to the end of the string. The simple question is, can there be problems when shifting by one character in a string consisting of one character (as in our case)?

The expression (X / 8)% 2 is just getting the fourth bit. For an unsigned integer this is equivalent to (X >> 3) & 1. Finally, an additional task is to check this statement for negative numbers.

Especially I will not give the text of the program. I believe that after all the hints this program can be easily written.

If you think this is a made-up example, then I can argue. Really comes across a code much harder to parse. And do not think that I urge to write such a horror.

For those who fall for such testing: the main thing here is not to be intimidated, you will probably be hired without this task.

For those who want to use for an interview: if you decide to give this task for an interview, and a smile flashes in the eyes of the applicant, it means that you both read this post. But you do not worry, let him repeat with an explanation ...

For readers: I know only one person who did this task right away (and it was not me).

PS
Thanks nwalker :
"This is one of the winners of IOCCC 1985 , shapiro.c by Carl Shapiro , the code draws a maze in stdout. ... In the process of the search, there was also an interesting post about obfuscation C and labyrinths: The art of obfuscation ."

Source: https://habr.com/ru/post/325880/


All Articles