N1570 утверждает, что это неопределенное поведение:
§J.2 / 1 Значение объекта с автоматической продолжительностью хранения используется, пока оно неопределено (6.2.4, 6.7.9, 6.8).
И в этом случае наш указатель имеет неопределенное значение:
§6.7.9 / 10 Если объект, который имеет автоматическую продолжительность хранения, не инициализируется явно, его значение является неопределенным. Если объект, который имеет статическую или длительность хранения streamов, не инициализируется явно, то:
- Обоснование для сравнения указателей вне массива должно быть UB
- Декларация статической переменной (C)
- Подписывается ли подписка на массив на адрес объекта?
- Как определить, равен ли указатель элементу массива?
- Каково определение «арифметической операции» в C99?
– если он имеет тип указателя, он инициализируется нулевым указателем;
Тогда я предполагаю, что следующая тестовая программа демонстрирует неопределенное поведение:
#include int main(void) { char * ptr; printf("%p", (void*)&ptr); }
Мое мотивирующее беспокойство – функция strtol
. Во-первых, позвольте мне процитировать части N1570, связанные с параметром endptr
:
§7.22.1.4 / 5 Если последовательность субъекта имеет ожидаемую форму и значение базы равно нулю, последовательность символов, начинающихся с первой цифры, интерпретируется как целочисленная константа в соответствии с правилами 6.4.4.1. […] Указатель на конечную строку хранится в объекте, на который указывает
endptr
, при условии, чтоendptr
не является нулевым указателем.§7.22.1.4 / 7 Если последовательность объектов пуста или не имеет ожидаемой формы, преобразование не выполняется; значение
nptr
сохраняется в объекте, на который указываетendptr
, при условии, чтоendptr
не является нулевым указателем.
Это означает, что endptr
должен указывать на объект, а также что endptr
в какой-то момент разыменовывается. Например, эта реализация делает так :
if (endptr != 0) *endptr = (char *)(any ? s - 1 : nptr);
Тем не менее, этот высокоподдерживаемый ответ, а также эта страница человека показывают, что endptr
передается strtol
uninitialized. Есть ли исключение, которое делает это не неопределенным поведением?
В этом выражении:
&ptr
адрес &
операнда, т. е. адрес объекта ptr
но объект ptr
никогда не оценивается.
(C11, 6.3.2.1p2) «За исключением случаев, когда это операнд оператора sizeof, унарный оператор &, оператор ++, оператор-оператор или левый операнд оператора. Или оператор присваивания, lvalue который не имеет тип массива, преобразуется в значение, хранящееся в указанном объекте (и уже не lvalue), это называется преобразованием lvalue. ”
Значение указателя и его адрес не совпадают.
void *foo;
Указатель имеет неопределенное значение, но адрес foo
, то есть значение &foo
, должен быть хорошо определен (поскольку в противном случае мы не можем получить к нему доступ).
По крайней мере, это мое интуитивное понимание, я сейчас не выкапывал стандарт, я просто думаю, что вы неправильно читаете его.
Когда вы говорите о коде, эти два иногда путают («что такое адрес этого указателя?» Может означать «каково значение этого указателя, на какой адрес он указывает?»), Но они действительно различны.
См. Этот пример
char * ptr;
Поскольку ptr
не указывает на какой-либо объект, разыменование его вызывает неопределенное поведение. Но когда вы передаете свой адрес strtol
, имея синтаксис
long int strtol(const char *nptr, char **endptr, int base);
в заявлении
long parsed = strtol("11110111", &ptr, 2);
параметр strtol
указывает на объект ptr
и отменяет его, не вызывая никакого UB.
Нет. Это не неопределенное поведение. Только ptr
неинициализирован и имеет неопределенное значение, но &ptr
имеет правильное значение.
Какая стандартная цитата на strtol
говорит:
… Если последовательность объектов пуста или не имеет ожидаемой формы, преобразование не выполняется; значение nptr сохраняется в объекте, на который указывает endptr, при условии, что endptr не является нулевым указателем.
Это выше цитаты говорит о вызове, подобном этому:
strtol(str, 0, 10);
Вызов на странице руководства и связанный с ним ответ в порядке.
У меня есть только доступ к N1256, но я буду удивлен, если произойдет какое-либо существенное изменение.
Наиболее важным разделом является «6.5.3.2 Операторы адреса и косвенности»
И, в частности, пункт 3 (мой акцент):
Семантика
3 Унарный оператор & дает адрес своего операнда. Если операнд имеет тип ” type ”, результат имеет тип ” указатель на тип ”. Если операнд является результатом унарного * оператора, ни этот оператор, ни оператор & не оцениваются, и результат, как если бы оба были опущены, за исключением того, что ограничения для операторов все еще применяются, а результат не является значением l. Аналогично, если операнд является результатом оператора [], ни оператор &, ни унарный *, который подразумевается [], не оцениваются, а результат выглядит так, как если бы оператор & был удален, а оператор [] был изменен на a +. В противном случае результатом будет указатель на объект или функцию, назначенные его операндом.
Ни один из приведенных абзацев в OP не применяется, поскольку многие из них указали. Значение чего-то и его адреса очень разные.
Я хотел бы утверждать, что отсутствие каких-либо ограничений в отношении неинициализированных ценностей, принимающих их адрес, разрешено (из-за отсутствия запрета).
ПРИМЕЧАНИЕ. Мы все знаем, что все в порядке, но очень редко можно найти утверждения в этих стандартах, которые прямо говорят «Да, вы можете так и так».