Scanf с const int * const работает, но не должен
У меня есть код, эквивалентный следующему:
const int* const n = new int;
printf("input: ");
scanf("%d", n);
delete n;
Теперь, поскольку n является указателем на целое число CONSTANT, это не должно работать (я ожидаю ошибку компилятора). Однако, похоже, это работает правильно и даже сохраняет значение ввода в * n.
Я хочу знать, почему это не дает мне ошибку; почему это работает? Если scanf не может изменить значение * n?
Ответы
Ответ 1
Прототипом scanf является:
int scanf ( const char * format, ... );
Эллипсис означает, что он принимает переменные аргументы. C (и С++) не имеют возможности проверить правильность этих параметров. Вот почему вы не получите ошибку, если вы передадите адрес двойной здесь или даже двойную переменную. Это до программиста, чтобы проверить правильный параметр.
Ответ 2
scanf
не имеет безопасности типа, он весело делает то, что вы ему рассказываете. Это происходит из-за того, как переменные-аргументы перечислены в C. Они ожидают, что типы будут такого типа, о которых вы говорите.
Итак, если вы даете scanf
спецификатор преобразования, который не соответствует, вы будете вызывать поведение undefined, которое происходит во время выполнения. Точно так же, вероятно, нет возможности компилятору сказать, что переданный указатель имеет тип const type* const
. Хороший компилятор может дать диагностику, если она обнаруживает что-то подозрительное, но отнюдь не требуется для этого.
Так как большинство случаев поведения undefined происходят во время выполнения, обычно ответственность программиста заключается в том, чтобы знать о различных формах поведения undefined и избегать их.
Ответ 3
Так как scanf
является переменным, он синтаксически закончен, чтобы пропускать почти что угодно, поэтому он тоже должен компилироваться.
Хотя n
является указателем на const int
, он указывает на объект, который фактически не является объектом const. Следовательно, изменение этого объекта int
(например, с помощью const_cast
для преобразования указателя на int*
) является корректным поведением.
Наконец, в стандартной документации fscanf
говорится
результат преобразования помещается в объект, на который указывает первый аргумент, следующий за аргументом формата, который еще не получил результат преобразования. Если этот объект не имеет соответствующего типа или если результат преобразования не может быть представлен в объекте, поведение undefined.
Указатель, фактически, указывает на объект соответствующего типа; в заключение я считаю, что это четко определенное (но запутанное) поведение.
Ответ 4
Компилятор может выдать предупреждение, но он не помешает вам совершать ошибки, как это, поведение undefined, const
используется как индикатор, оно не предотвращает компиляцию. И он работает правильно, потому что указатель не действительно const
, хотя он undefined BEHAVIOR передает указатель const
, но это на самом деле не один.
Ответ 5
Ну, scanf
не будет различать переданные аргументы, но если вы скомпилируете с включенными предупреждениями, компилятор предупредит вас об этом -
warning: writing into constant object (argument 2) [-Wformat]