if ... fi
#define IF if( #define THEN ){ #define ELSE } else { #define FI ;}
IF *s2++ == 0 THEN return(0); FI
Avoid any use of the C preprocessor, which changes the base language.
main(){printf(&unix["\021%six\012\0"], (unix)["have"]+"fun"-0x60);}
unix
unix
, but it has not been declared. Then unix
is a keyword? Does it somehow print the name of the variable? printf(unix);
printf
accepts char *
, not int
.int
, it became clear that its value is 1. This gave me the idea that it was redefined as if the code were compiled on a Unix system. Searching for gcc source code , I found it to be a run-time target specification . This explains why the code will not run on Windows.unix
is just 1. Having rewritten, we get: main(){printf(&1["\021%six\012\0"], (1)["have"]+"fun"-0x60);}
unix
not a variable name. But then how does 1 [] work? I have seen this before, and this is one of my favorite facts about the C language.The operator of indirect treatment! accepts a pointer as an argument and returns the contents of the cell to which it points. If v is a pointer, then! (V + i) will refer to the cell with the address v + i. Binary version of the operator! is defined so that v! i =! (v + i). v! i behaves like an indexed view, where v is a one-dimensional array, and i is an integer type index. Note that in the language of BCPL, v5 =! (V + 5) =! (5 + v) = 5! V. The same happens in the C language: v [5] = 5 [v].
int x[] = {1, 2, 3}; printf("%d\n%d\n", x[1], 1[x]);
1["\021%six\012\0"]
? Writing in the usual way, we will see access to the elements of the array through the indexing operator: "\021%six\012\0"[1]
. All the same, it is atypical, but it is already clear that this is array[index]
, although, as a rule, string literals do not use it that way. But it works, so try the following: printf("%c\n", "hello, world"[1]);
main() { char str[] = "\021%six\012\0"; printf(&str[1], (1)["have"]+"fun"-0x60); }
str
, I thought about the \0
, which is the null character (or the NUL character?). I thought that string literals in C have a null character by default. Let's see what happens if we remove it: printf("%s", "\021%six\012");
%six
"%s"
because the string I am trying to output contains the formatting character %
. (A little hint: do not print lines like printf(myStr)
when they have formatting characters. The output in %s
shown above.)\0
. Maybe in some pre-ANSI C did you have to add null characters yourself to string literals? I think not, because other lines in the program do not have them. Or does it just look more confusing? Okay, let's leave this \0
.\xxx
is the representation of each character in the octal number system, \021
is a control character, and \012
is a newline character or \n
, as we used to see it, at the end of the output lines.\021
is just one character, we understand that str[1]
is %
. Then &str[1]
is a string starting with %
. So the line can actually be just %six\n
, without a control character, which is not clear why you need it here. main() { char str[] = "%six\n"; printf(str, (1)["have"]+"fun"-0x60); }
printf
is the formatting line, %s
means "put the following line instead of this one". Since this line ends with ix
, it can be assumed that the next line passed to printf
should somehow look like un
. Easily get rid of the array of characters that we used to pass the formatting string, and we get: main() { printf("%six\n", (1)["have"]+"fun"-0x60); }
(1)["have"]+"fun"-0x60
. There is an un
that is contained in the word fun
, so let's break it down.(1)["have"]
. Parentheses around 1 are not needed. Again, was it required in old C or made for more unreadable? "have"[1]
is a
. In hexadecimal notation, it looks like 0x61, subtracts 0x60. Then there will be 1+"fun"
."fun"
stands for char *
. Adding 1 gives us a line starting with the second character, that is, un
. Then everything turns into this: main() { printf("%six\n", "un"); }
unix
to confuse you and make you think that it is redefined and in some way deduces its name. The symbol \021
is similar to the inverted \012
and can make you think that it is necessary, although, in fact, it is not used. There is also a %six
formatting string containing the word "six", apparently, so that you take% s not for formatting, but for something else.Source: https://habr.com/ru/post/313598/
All Articles