2016-04-21 6 views
0

В последнее время я пытаюсь проработать некоторые основы C, чтобы попытаться создать базовое понимание языков более низкого уровня. В одном из документов, с которыми я столкнулся (A tutorial on pointers and arrays in C) автор использует указатель недействительным в printf заявлении:Указатель на удаление при печати

int var = 2; 
printf("var has the value %d and is stored at %p\n", var, (void *) &var); 

И утверждает причину:

Я ввергнуть указатели на целые числа в void Указатели, чтобы сделать их совместимыми со спецификацией преобразования% p.

Однако, опуская (void *) не приводит к ошибке или предупреждение, либо компиляции и выполнения или через valgrind.

int var = 2; 
printf("var has the value %d and is stored at %p\n", var, &var); 

Является ли кастинг недействительным здесь считается лучшей практикой или стандартом, или есть что-то более зловещее?

+0

Невозможно проверить экспериментально, правильно ли вы написали C. Программа правильная C, если она соответствует правилам, это все, что вы можете сделать. –

+0

Это просто явное выражение, буквально говорит: «Я беру эту ценность, чтобы ее толковали именно так». В вашем примере вы используете 'int *' для 'void *'. Поэтому возьмите мой целочисленный указатель, чтобы интерпретировать его как общий указатель. Лично, быть настолько многословным, не кажется большой практикой для подобных тривиальных ситуаций. – SGM1

+1

Указателям на разные типы разрешено иметь разные представления и ограничения выравнивания. 'printf()' - это вариационная функция, которая автоматически не преобразует свои аргументы в тип своих параметров, поэтому вызов его с аргументами неправильного типа приводит к неопределенному поведению. – EOF

ответ

4

С printf является вариационной функцией, ее декларация указывает только тип первого параметра (строка формата). Количество и типы любых оставшихся параметров необходимы для соответствия строкам формата, но вам решать, программист, чтобы убедиться, что они действительно совпадают. Если они этого не делают, поведение не определено, но компилятор не обязан предупреждать вас об этом. (Некоторые компиляторы, в том числе gcc, могут выполнить некоторую проверку, является ли строка формата литералом.)

Спецификатор формата %p требует аргумента типа void*. Если вы передаете указатель другого типа, у вас есть неопределенное поведение. Во многих реализациях все типы указателей имеют одинаковый размер и представление и передаются так же, как аргументы функции, но язык этого не гарантирует. Явным образом преобразовывая указатель в void*, вы гарантируете, что он будет работать правильно. Опустив приведение, у вас есть код, который будет , вероятно, работает так, как вы ожидаете, почти на всех реализациях.

100% правильный лучше 99% правильно, особенно если единственная стоимость этого дополнительного 1% набирает несколько символов.

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