C language test found in an April Fool’s joke
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 can be used to determine the depth of a person's understanding of the C language. This line will also work in C ++. I advise you to try your hand. It will not be funny. Perhaps it will be useful.
At the dawn of his career as a programmer, a friend showed me an article about the fact that C and UNIX are an April Fools' joke. The above line of code was used as evidence of the absurdity of the language. In my opinion, quite working. After some time during the interview, this joke was remembered. As with many other tests, it is not the result that matters (it sets the goal of the work), but the process of analysis and understanding.
Where we got the article I don’t 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 a second backslash appeared in the string "\ n".
Try to figure out the task yourself. Do not think about the meaning of the program for now.
for ( ; P("\n"), R--; P("|"))
for (e = C; e--; P("_" + (*u++ / 8) % 2))
P("| " + (*u / 4) % 2);This is very easy if you saw the text of normal programs. You can close your eyes to spaces, but loops should be on different lines with different indents.
#include
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 we need include? And is he needed here? Is it possible without return? And a very cruel question. What are the parameters of the main function?
Do not be lazy, and try to answer these questions yourself.
for ( ; P("\n"), R--; P("|"))Here we meet a very simple problem. There is no initializer (after the open bracket, immediately followed by a semicolon). It bothers some. This often happens if a person writes programs in another language, for example, in Pascal.
A real stumbling block, even for experienced enough programmers, comes across the expression "P (" \ n "), R--." Many simply do not know that there is such a “comma” operation, and that the result of its work will be the result of the expression after the comma. The expression before the decimal point is also calculated, but its result is not used. Moreover, this operation has the lowest priority . Therefore, first P ("\ n") is executed, and then R--.
The result of the expression R-- here is a condition for fulfillment. This also confuses some, although this technique is often used. Many programmers find it unnecessary to write in conditional if statements, expressions like if (a! = 0) ... 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 a small one).
Usually, upon reaching here, it is already clear to everyone that there is a function P that takes a string as input. There are no problems. You must declare this function. Since the meaning is not important to us, it can even be empty. I prefer the function that displays text on the screen (here, the pre-written #include came in handy
for (e = C; e--; P("_" + (*u++ / 8) % 2) )Everything in the cycle is already familiar. The decrement is in the check on the execution of the cycle, as was above. We add the variable e, similar to R. You can immediately declare a variable C of the same type, although it can be a constant, or even define. Here is the will of the author.
Of interest here is the call to function P.
P("_" + (*u++ / 8) % 2) If we look further, we will see a similar construction in the function body.
P("| " + (*u / 4) % 2);It’s worth it to be patient. The goal is close. This is the crown of this "masterpiece". Do not rush to open the following explanation, think.
"_" + (*u++ / 8) % 2"| " + (*u / 4) % 2Next, we will consider the first expression. It is more complex. It is clear that here the expression in parentheses is calculated first, then the remainder of dividing by 2 is taken from it, at the end this number is added to the line.
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 independent 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 operation is integer division, and integer dividend. For novice programmers, the expression * u ++ can cause uncertainty: in the presence of a post-increment in the expression and in the priority of performing post-increment operations and dereference of the pointer. This technique is sometimes used in C programs when moving through an array. The expression returns the value at the current pointer (before incrementation) and shifts the pointer to the next element. Therefore, the variable u is not just a pointer, but also an array. An additional question is, what size (in elements) should this array be?
The most “beautiful” trick is adding a number to the string. It must be remembered that this is the C language. Do not wait for the conversion of a number to a string, and even more so a string to a number. Everything is much stranger than it might seem at first glance, but it is 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 the address shifted relative to the original pointer by a given number of elements. In this example, after receiving the remainder of dividing by 2, either 0 or 1 comes out. Accordingly, either we pass the string to the function P without offset (as it is), or we shift one character to the end of the string. A simple question, can there be problems when shifting by one character in a line 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. And in conclusion, 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 prompts this program can be easily written.
If you think this is a fictitious example, then I can bet. Really comes across a much more difficult code to parse. And do not think that I urge you to write such horror.
For those who fall for such testing: the main thing here is not to be scared, 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 do not be discouraged, let him repeat with an explanation ...
For readers: I know only one person who did this task right away (and it wasn’t me).
PS
thanksnwalker :
“This is one of the winners of IOCCC 1985 , shapiro.c by Carl Shapiro , the code draws a labyrinth in stdout. ... In the search process, I also found an interesting post about obfuscation C and labyrinths: The art of obfuscation .”