2014-12-26 5 views
5

Я понимаю, что если printf не имеет аргументов, он выводит неожиданное значение.Printf без объяснений аргументов

Пример:

#include <stdio.h> 

int main() { 
    int test = 4 * 4 

    printf("The answer is: %d\n"); 
    return 0; 
} 

Это возвращает случайное число. После воспроизведения в разных форматах, таких как% p,% x и т. Д., Он не печатает 16 (потому что я не добавлял переменную в раздел аргумента). Мне хотелось бы знать, где берутся эти значения из? Это вершина стека? Это не новое значение каждый раз, когда я компилирую, что странно, это как фиксированное значение.

+2

Это неопределенное поведение. Тот факт, что он кажется исправленным, - счастливая случайность. Это может быть из стека, может быть, из реестра ... вы не знаете, наплевать на него. –

+0

1. С 'printf (« Ответ:% d \ n »)', вы передаете ** один ** аргумент. 2. Если этот аргумент указывает на строку с нулевым завершением, которая не содержит символ '' '' '' ', то' printf' выведет ожидаемое значение. –

ответ

5
printf("The answer is: %d\n"); 

вызывает неопределенное поведение. C требуется спецификатор преобразования, чтобы иметь связанный аргумент. Хотя это неопределенное поведение и что-то может случиться, на большинстве систем вы в конечном итоге сбрасываете стек. Это трюк, используемый в format string attacks.

4

Это называется undefined behavior, и это страшно (см. this answer).

Если вам требуется объяснение, вам необходимо погрузиться в конкретные детали реализации. Поэтому изучите сгенерированный исходный код (например, скомпилируйте с помощью gcc -Wall -Wextra -fverbose-asm + ваши флаги оптимизации, затем просмотрите сгенерированный файл сборки .s) и ABI вашей системы.

+0

Ага, я люблю ответ, который вы предоставили. И хорошо, тогда я пойду осмотрю это. – sbnation

1

Printf - это переменная функция аргумента. Большинство компиляторов выставляют аргументы в стек, а затем вызывают функцию, но в зависимости от машины, операционной системы, соглашения о вызовах, количества аргументов и т. Д. В стеке также добавляются другие значения, которые могут быть постоянными в вашей функции.

Printf считывает эту область памяти и возвращает ее.

2

Функция printf будет искать аргумент в стеке, даже если вы его не доставляете. Все, что там будет, будет использовано, если оно не может найти целочисленный аргумент. В большинстве случаев вы получите бессмысленные данные. Выбранные данные различаются в зависимости от настроек вашего компилятора. В некоторых компиляторах вы можете получить 16 в результате.

Например:

int printf(char*, int d){...} 

Это было бы, как Printf работы (не очень, просто пример). Он не возвращает ошибку, если d является нулевым или пустым, он просто смотрит на стек для аргумента, который должен отображаться там.

+0

В некоторых ABI переменные функции вызывают иначе, чем функции фиксированной arity. –

Смежные вопросы