int *ptr = 10000;
Это не просто неопределенное поведение. Это нарушение ограничения .
Выражение 10000
имеет тип int
. ptr
имеет тип int*
. Нет никакого неявного преобразования из int
в int*
(за исключением специального случая константы нулевого указателя, которая здесь не применяется).
Любой соответствующий C-компилятор, при обработке этого объявления, должен выдать диагностическое сообщение. Разрешено для этого сообщения быть нефатальным предупреждением, но после того, как оно выдается этим сообщением, поведение программы не определено.
Компилятор может рассматривать его как фатальную ошибку и отказываться от компиляции вашей программы. (На моем взгляде, составители должны сделать это.)
Если вы действительно хотите, чтобы назначить ptr
, чтобы указать адрес 10000
, вы могли бы написать:
int *ptr = (int*)10000;
Там нет неявного преобразования из int
до int*
, но вы можете сделать явным образом конвертация с литым оператором.
Это правильная вещь, если вам известно, что 10000
является действительным адресом для машины, на которой будет работать ваш код. Но в целом результат преобразования целого числа в указатель «определяется реализацией, может быть неправильно выровнен, может не указывать на объект ссылочного типа и может быть ловушечным представлением» (N1570, раздел 6.3.2.3). Если 10000
не является допустимым адресом (и это, вероятно, не так), то ваша программа все еще имеет неопределенное поведение, даже если вы пытаетесь получить доступ к значению указателя, но особенно если вы попытаетесь разыменовать его.
Это также предполагает, что преобразование целочисленного значения 10000
в тип указателя имеет смысл. Обычно такое преобразование копирует биты числового значения, но стандарт C не говорит об этом. Это может сделать некоторые странные преобразования, определенные реализацией, для создания адреса.
Адреса (значения указателя) не являются номерами.
printf("value: %d\n", ptr);
Это определенно имеет неопределенное поведение. Формат %d
требует аргумента int
. На многих системах int
и int*
не имеют одинакового размера. Вы можете в конечном итоге напечатать, скажем, верхнюю половину значения указателя или даже полный мусор, если целые числа и указатели не передаются в качестве аргументов функции таким же образом. Чтобы напечатать указатель, используйте %p
и преобразовать указатель на void*
:
printf("value: %p\n", (void)ptr);
Наконец:
printf("value: %d\n", *ptr);
Строка формата является правильным, но только оценки *ptr
имеет неопределенное поведение (если (int*)10000
не случается, действительный адрес).
Обратите внимание, что «неопределенное поведение» не означает, что ваша программа будет аварийно завершена. Это означает, что в стандарте указано ничего о том, что произойдет, когда вы запустите его. (Сбои, вероятно, лучше всего возможного результата, это делает очевидным, что это ошибка.)
'** ptr = 10;' не следует компилировать с ошибкой 'error: недопустимый аргумент типа унарного '*' (иметь 'int')'. Что ты сделал? – MikeCAT
Возможный дубликат [Прямое присвоение значений C Указателям] (http://stackoverflow.com/questions/17665793/directly-assigning-values-to-c-pointers) – Olaf
@MikeCAT, вы правы .. Я перефразировал мои вопрос. Просто хочу убедиться, что первая часть моего понимания верна. – user2001996