Подтвердить что ты не робот

C Код: Как они работают?

Я только что увидел это здесь

#include <stdio.h>

int main(int argc, char *argv[printf("Hello, world!\n")]) {}

Что это значит, это "Hello World!"

Но что на самом деле происходит здесь?

Самое лучшее, что я могу догадаться, это то, что он скомпилирован и добавлен в верхнюю часть стека выполнения, но синтаксис даже не выглядит законным для меня...

4b9b3361

Ответ 1

В коде используется функция массива переменной длины C99, которая позволяет объявлять массивы, размер которых известен только во время выполнения. printf возвращает целое число, равное количеству символов, которые были на самом деле напечатаны, поэтому код печатает "Hello, world!". сначала и использует возвращаемое значение как размер argv. Сама функция main ничего не делает. Фактический вызов printf сам, вероятно, входит в код запуска, сгенерированный компилятором, который, в свою очередь, вызывает main.

Изменить: Я только что проверил разбор кода, сгенерированного gcc, и кажется, что вызов printf входит внутрь main непосредственно перед любым другим кодом.

Ответ 2

Если я выясню, как компилятор проанализировал его, я обновлю это, но, по крайней мере, не должно быть никаких догадок о том, как он скомпилирован:


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 <[email protected]>
 80483da:       c9                      leave  
 80483db:       c3                      ret    
 80483dc:       90                      nop
 80483dd:       90                      nop
 80483de:       90                      nop
 80483df:       90                      nop

Поскольку исполняемые файлы Linux обычно основаны на 0x8048000, адрес аргумента printf имеет смещение 0x00004a0 от начала двоичного файла:


xxd /tmp/hello | grep 00004a0

00004a0: 4865 6c6c 6f2c 2077 6f72 6c64 210a 0000  Hello, world!...

Итак, адрес строки нажат, а printf вызывается с одним аргументом. Ничего волшебного на этом уровне, поэтому все забавные вещи были сделаны gcc.

Ответ 3

char *argv[printf("Hello, world!\n")])

printf() возвращает количество напечатанных символов.

So

int main(int argc, char *argv[printf("Hello, world!\n")]) {}

эквивалентно

int main(int argc, char *argv[14]) {}

плюс вызов printf(), который печатает "Hello World"

Ответ 4

Я не эксперт от C, но похоже, что аргументы командной строки объявляются одновременно с main.