Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C Code: How does these even work?

Tags:

I just saw this here

#include <stdio.h>  int main(int argc, char *argv[printf("Hello, world!\n")]) {} 

What this does is print "Hello World!"

But what's actually going on here?

The best I can guess is that it gets compiled and thrown at the top of the execution stack, but the syntax doesn't even look legal to me ...

like image 404
Reverend Gonzo Avatar asked Nov 11 '10 03:11

Reverend Gonzo


People also ask

How do C codes work?

c is called the source file which keeps the code of the program. Now, when we compile the file, the C compiler looks for errors. If the C compiler reports no error, then it stores the file as a . obj file of the same name, called the object file.

Is C still used in 2022?

C is one of the earliest and most widely used programming languages. C is the fourth most popular programming language in the world as of January 2022. Modern languages such as Go, Swift, Scala, and Python are not as popular as C.

What does <= mean in C?

Less than or equal to operator is a logical operator that is used to compare two numbers.

Is C programming hard?

C is more difficult to learn than JavaScript, but it's a valuable skill to have because most programming languages are actually implemented in C. This is because C is a “machine-level” language. So learning it will teach you how a computer works and will actually make learning new languages in the future easier.


2 Answers

The code makes use of C99's variable-length array feature, which lets you declare arrays whose size is known only at run-time. printf returns an integer equal to the number of characters that were actually printed, so the code prints "Hello, world!" first and uses the return value as the size of argv. The main function itself does nothing. The actual call to printf itself probably goes into the startup code generated by the compiler, which in turn calls main.

Edit: I just checked the disassembly of the code generated by gcc and it appears that the call to printf goes inside main itself, before any other code.

like image 92
casablanca Avatar answered Oct 12 '22 09:10

casablanca


If I figure out how the compiler parsed it, I'll update this, but at least there needs to be no guesswork as to how it compiled:

 objdump --disassemble /tmp/hello (edited):  080483c4 <main>:  80483c4:       55                      push   %ebp  80483c5:       89 e5                   mov    %esp,%ebp  80483c7:       83 e4 f0                and    $0xfffffff0,%esp  80483ca:       83 ec 10                sub    $0x10,%esp  80483cd:       b8 a0 84 04 08          mov    $0x80484a0,%eax  80483d2:       89 04 24                mov    %eax,(%esp)  80483d5:       e8 22 ff ff ff          call   80482fc <printf@plt>  80483da:       c9                      leave    80483db:       c3                      ret      80483dc:       90                      nop  80483dd:       90                      nop  80483de:       90                      nop  80483df:       90                      nop 

Since Linux executables are based normally at 0x8048000, the address of the argument to printf is at an offset of 0x00004a0 from the start of the binary:

 xxd /tmp/hello | grep 00004a0  00004a0: 4865 6c6c 6f2c 2077 6f72 6c64 210a 0000  Hello, world!... 

So, the address of the string is pushed, and printf is called with that one arg. Nothing magical at that level, so all the fun stuff was done by gcc.

like image 45
jcomeau_ictx Avatar answered Oct 12 '22 10:10

jcomeau_ictx