Tell me more ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

Why does this code gives output C++Sucks? Can anyone explain the concept behind it?

#include <cstdio> 
double m[]= {7709179928849219.0, 771};
int main()
{
    m[1]--?m[0]*=2,main():printf((char*)m);    
}

Here is the Ideone link: http://ideone.com/PM4qan

share|improve this question
33  
Magic! And a bit of recursion. But mostly magic. – nijansen 17 hours ago
21  
Don't forget Undefined Behaviour! – BoBTFish 17 hours ago
9  
@BobTFish The coolest tricks in C always rely on UB, that's why it's impossible to get a 20 yr old game running on a modern machine. – nijansen 17 hours ago
52  
C++ only sucks the way the author of this code uses it. – John Dibling 17 hours ago
42  
He could just do puts("C++Sucks");. Those C people always over-complicate simple things. – Maxim Yegorushkin 14 hours ago
show 15 more commentsadd comment (requires an account with 50 reputation)

8 Answers

up vote 182 down vote accepted

The number 7709179928849219.0 has the following binary representation as a 64-bit double:

01000011 00111011 01100011 01110101 01010011 00101011 00101011 01000011
+^^^^^^^ ^^^^---- -------- -------- -------- -------- -------- --------

+ shows the position of the sign; ^ of the exponent, and - of the mantissa (i.e. the value without the exponent).

Since the representation uses binary exponent and mantissa, doubling the number increments the exponent by one. Your program does it precisely 771 times, so the exponent which started at 1075 (decimal representation of 10000110011) becomes 1075 + 771 = 1846 at the end; binary representation of 1846 is 11100110110. The resultant pattern looks like this:

01110011 01101011 01100011 01110101 01010011 00101011 00101011 01000011
-------- -------- -------- -------- -------- -------- -------- --------
0x73 's' 0x6B 'k' 0x63 'c' 0x75 'u' 0x53 'S' 0x2B '+' 0x2B '+' 0x43 'C'

This pattern corresponds to the string that you see printed, only backwards. At the same time, the second element of the array becomes zero, providing null terminator, making the string suitable for passing to printf.

share|improve this answer
6  
Why is the string backwards? – Derek 15 hours ago
18  
@Derek x86 is little-endian – Angew 15 hours ago
7  
@Derek This is because of the platform-specific endianness: the bytes of the abstract IEEE 754 representation are stored in memory at decreasing addresses, so the string prints correctly. On hardware with big endianness one would need to start with a different number. – dasblinkenlight 15 hours ago
4  
@AlvinWong You are correct, the standard does not require IEEE 754 or any other specific format. This program is about as non-portable as it gets, or very close to it :-) – dasblinkenlight 13 hours ago
3  
@GrijeshChauhan I used a double-precision IEEE754 calculator: I pasted the 7709179928849219 value, and got the binary representation back. – dasblinkenlight 8 hours ago
show 6 more commentsadd comment (requires an account with 50 reputation)

More readable version:

double m[2] = {7709179928849219.0, 771};
// m[0] = 7709179928849219.0;
// m[1] = 771;    

int main()
{
    if (m[1]-- != 0)
    {
        m[0] *= 2;
        main();
    }
    else
    {
        printf((char*) m);
    }
}

It recursively calls main() 771 times. In the beginning m[0] = 7709179928849219.0, which stands for C++Suc;C. In every call, m[0] gets doubled, to "repair" last two letters. In the last call, m[0] contains ASCII char representation of C++Sucks. It's assuming that m[0] is stored on 8 bytes, so each char takes 1 byte. m[1] contains all zeros, so it has a null terminator for C++Sucks string.

Without recursion and illegal main() calling it will look like this:

double m[] = {7709179928849219.0, 0};
for (int i = 0; i < 771; i++)
{
    m[0] *= 2;
}
printf((char*) m);
share|improve this answer
1  
It's postfix decrement. So it will be called 771 times. – Jack Aidley 17 hours ago
1  
@JackAidley You're right, thanks. I've edited my answer. – Adam Stelmaszczyk 17 hours ago
1  
Excellent answer. – Nathan 15 hours ago
2  
this should be the accepted answer, really clears the 'obfuscation' of the original code. – gandolf 11 hours ago
add comment (requires an account with 50 reputation)

Formally speaking, it's impossible to reason about this program because it's ill-formed (i.e. it's not legal C++). It violates C++11[basic.start.main]p3:

The function main shall not be used within a program.

This aside, it relies on the fact that on a typical consumer computer, a double is 8 bytes long, and uses a certain well-known internal representation. The initial values of the array are computed so that when the "algorithm" is performed, the final value of the first double will be such that the internal representation (8 bytes) will be the ASCII codes of the 8 characters C++Sucks. The second element in the array is then 0.0, whose first byte is 0 in the internal representation, making this a valid C-style string. This is then sent to output using printf().

Running this on HW where some of the above doesn't hold would result in garbage text (or perhaps even an access out of bounds) instead.

share|improve this answer
13  
I have to add that this is not an invention of C++11 - C++03 also had basic.start.main 3.6.1/3 with the same wording. – sharptooth 17 hours ago
The point of this small example is to illustrate what can be done with C++. Magic sample using UB tricks or huge software packages of "classic" code. – SChepurin 17 hours ago
1  
+1 for probably better explanation. – D.R. 17 hours ago
@sharptooth Thanks for adding this. I didn't mean to imply otherwise, I just cited the standard I used. – Angew 17 hours ago
@Angew: Yeap, I understand that, just wanted to say that the wording is pretty old. – sharptooth 17 hours ago
add comment (requires an account with 50 reputation)

It is just building up a double array (16 bytes) which - if interpreted as a char array - build up the ASCII codes for the string "C++Sucks"

However, the code is not working on each system, it relies on some of the following undefined facts:

  • double has exactly 8 bytes
  • double is represented in a certain way
share|improve this answer
add comment (requires an account with 50 reputation)

The following code prints C++Suc;C, so the whole multiplication is only for the last two letters

double m[] = {7709179928849219.0, 0};
printf("%s\n", (char *)m);
share|improve this answer
add comment (requires an account with 50 reputation)

The others have explained the question pretty thoroughly, I'd like to add a note that this is undefined behavior according to the standard.

C++11 3.6.1/3 Main function

The function main shall not be used within a program. The linkage (3.5) of main is implementation-defined. A program that defines main as deleted or that declares main to be inline, static, or constexpr is ill-formed. The name main is not otherwise reserved. [ Example: member functions, classes, and enumerations can be called main, as can entities in other namespaces. —end example ]

share|improve this answer
1  
I'd say it's even ill-formed (as I did in my answer) - it violates a "shall". – Angew 12 hours ago
add comment (requires an account with 50 reputation)

The code could be re-written like this:

void f()
{
    if (m[1]-- != 0)
    {
        m[0] *= 2;
        f()
    } else {
          printf((char*)m);
    }
}

What it's doing is producing a set of bytes in the double array m that happen to correspond to the characters 'C++Sucks' followed by a null-terminator. They've obfuscated the code by choosing a double value which when doubled 771 times produces, in the standard representation, that set of bytes with the null terminator provided by the second member of the array.

Note that this code wouldn't work under a different endian representation. Also, calling main() is not strictly allowed.

share|improve this answer
2  
Why does your f return an int? – leftaroundabout 16 hours ago
1  
Er, 'cos I was brainless copying the int return in the question. Let me fix that. – Jack Aidley 13 hours ago
add comment (requires an account with 50 reputation)

Its basically just a clever way to hide the String "C++Sucks" (note the 8 Bytes) within the first double value, which is recursively multiplied with 2 until the seconds double values reaches zero. (771 times)

Multiplying the double values 7709179928849219.0 * 2 * 711 results in "C++Sucks" if you interpret the byte-value of the double as string, which printf() does with the cast. And printf() doesn't fail, because the second double value is "0" and interpreted as "\0" by printf().

share|improve this answer
add comment (requires an account with 50 reputation)

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.