Поведение printf при печати %d, не предоставляя имя переменной

Проблема была в параметрах. Если я установлю параметр как строковую переменную из приложения логики и в моем sql SP используйте этот параметр как cast(@param as varchar(10)), все в порядке.

11
задан Aravindhan 28 June 2012 в 17:34
поделиться

6 ответов

Вы говорите, что "удивительно программа компилирует". На самом деле это не удивительно вообще. C & C ++ позволяет, чтобы функции имели списки аргумента переменной. Определение для printf - что-то вроде этого:

int printf(char*, ...);

"..." показывает, что существует нуль или больше дополнительных аргументов к функции. На самом деле одна из главных причин C имеет дополнительные аргументы, должен поддерживать printf и scanf семейство функций.

C не имеет никаких специальных знаний функции printf. В Вашем примере:

printf("%d");

Компилятор не анализирует строку формата и решает, что целочисленный аргумент отсутствует. Это - совершенно легальный код C. То, что Вы пропускаете аргумент, является семантической проблемой, которая только появляется во времени выполнения. Функция printf предположит, что Вы предоставили аргумент и идете, ища его на стеке. Это возьмет что бы ни случилось для хождения там. Это просто происходит, что в Вашем особом случае это печатает правильную вещь, но это - исключение. В целом Вы получите данные мусора. Это поведение будет варьироваться от компилятора до компилятора и также изменится, в зависимости от каких опций компиляции Вы используете; при включении оптимизации компилятора, Вы, вероятно, получите различные результаты.

Как указано в одном из комментариев к моему ответу, некоторые компиляторы имеют "линт" как возможности, которые могут на самом деле обнаружить ошибочные вызовы printf/scanf. Это включает компилятор, анализирующий строку формата и определяющий количество дополнительных ожидаемых аргументов. Это - совершенно особое поведение компилятора и не обнаружит ошибки в общем случае. т.е. если Вы запишете свою собственную функцию "printf_better", которая имеет ту же подпись как printf, то компилятор не обнаружит, если какие-либо аргументы будут отсутствовать.

25
ответ дан 3 December 2019 в 01:34
поделиться

То, что происходит, похоже на это.

printf("%d", m);

В большинстве систем адрес строки будет спешиться стек, и затем 'm' как целое число (принятие это - международное/короткое/символьное). Нет никакого предупреждения потому что printf в основном объявляется как 'int printf(const char *, ...);' -... значение 'что-либо идет'.

Таким образом, так как 'что-либо идет' некоторые нечетные вещи, происходят, когда Вы помещаете переменные там. Любой целочисленный тип, меньший, чем интервал, идет как интервал - подобные вещи. Отправка ничего во все в порядке также.

В printf реализации (или по крайней мере 'простой' реализации) Вы найдете использование va_list и va_arg (имена когда-то отличаются немного на основе соответствия). Это то, что реализация использует для обхода вокруг '...' часть списка аргументов. Проблема здесь состоит в том, что нет НИКАКОЙ проверки типа. С тех пор нет никакой проверки типа, printf вытянет случайные данные от стека выполнения, когда это посмотрит на строку формата ("%d") и думает, там, как предполагается, 'int' далее.

Случайный выстрел в темноте сказал бы, что вызов функции, который Вы сделали незадолго до printf возможно, передал 'm-1' поскольку это - второй parm? Это - одна из многих возможностей - но было бы интересно, если бы это, оказалось, имело место.:)

Удачи.

Между прочим - большинство современных компиляторов (GCC я верю?) имеют предупреждения, которым можно позволить обнаружить эту проблему. Линт делает также, я верю. К сожалению, я думаю с VC, необходимо использовать/, анализируют флаг вместо того, чтобы добраться бесплатно.

9
ответ дан 3 December 2019 в 01:34
поделиться

Это получило интервал от стека.

http://en.wikipedia.org/wiki/X86_calling_conventions

3
ответ дан 3 December 2019 в 01:34
поделиться

В то время как я высоко сомневался бы, что это приведет к нарушению памяти, целое число, которое Вы получаете, является неопределенным мусором.

1
ответ дан 3 December 2019 в 01:34
поделиться

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

0
ответ дан 3 December 2019 в 01:34
поделиться

Вы взаимодействуете в стек. Измените значения оптимизатора, и это может измениться. Измените порядок объявлений Ваши переменные (особенно) m. Сделать m регистровая переменная. Сделать m глобальная переменная.

Вы будете видеть некоторые вариации в том, что происходит.

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

1
ответ дан 3 December 2019 в 01:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: