2015-09-27 6 views
-2

я прочиталНепосредственно объявить и присвоить значение указателей C

Directly assigning values to C Pointers

Однако, я пытаюсь понять это по другому сценарию ...

int *ptr = 10000; 
printf("value: %d\n", ptr); 
printf("value: %d\n", *ptr); 

я получил ошибку сегментации на второй printf.

Теперь у меня создается впечатление, что 10000 является местом памяти, поскольку указатели указывают на адрес в памяти. Я также знаю, что 10000 может быть где угодно в памяти (что уже может быть занято каким-то другим процессом)

Поэтому я думаю, что первый отпечаток просто говорит, что «хорошо, просто дайте мне значение адрес как какое-то целочисленное значение ", так что, я получил 10000.

Тогда я говорю« хорошо, теперь уважаю это для меня », но я ничего не вкладывал в это (или он неинициализирован), поэтому я получил ошибку сегментации.

Возможно, моя логика уже полностью отключена от этой дорожки и эта точка.

ОБНОВЛЕНО ::::

Спасибо за все быстрый ответ .. Так вот мое понимание.

Первый, int * ptr = 10000; UB, потому что я не могу назначить указатель на постоянное значение.

Во-вторых, следующее UB, потому что вместо использования% p я использую% d. printf ("value:% d \ n", ptr)

В-третьих, я указал адрес (хотя это UB), но я не инициализировал какое-либо значение, поэтому следующее выражение получило ошибку seg. print ("значение:% d \ n", * ptr)

Мое понимание сейчас?

спасибо.

+0

'** ptr = 10;' не следует компилировать с ошибкой 'error: недопустимый аргумент типа унарного '*' (иметь 'int')'. Что ты сделал? – MikeCAT

+2

Возможный дубликат [Прямое присвоение значений C Указателям] (http://stackoverflow.com/questions/17665793/directly-assigning-values-to-c-pointers) – Olaf

+0

@MikeCAT, вы правы .. Я перефразировал мои вопрос. Просто хочу убедиться, что первая часть моего понимания верна. – user2001996

ответ

0

Это может привести к неопределенному поведению, поскольку указатель, преобразованный из 10000, может быть недействительным.

Ваша ОС может не разрешить вашей программе получать доступ к адресу 10000, так что это приведет к сбою сегментации.

int *x = some numerical value (i.e. 10, whatever)

может быть для микрокомпьютеров или низкого уровня (например: создание ОС).

+0

@Olaf. Тем не менее, мое понимание правильное, хотя я могу напечатать ptr, потому что это просто ценность, которую я дал, и ничего больше? – user2001996

+0

@ user2001996: Печать указателя, инициализированного недопустимым типом, уже является UB. – Olaf

+0

извините, я не знаю, что означает UB ... – user2001996

1
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 не случается, действительный адрес).

Обратите внимание, что «неопределенное поведение» не означает, что ваша программа будет аварийно завершена. Это означает, что в стандарте указано ничего о том, что произойдет, когда вы запустите его. (Сбои, вероятно, лучше всего возможного результата, это делает очевидным, что это ошибка.)

+0

спасибо за объяснение. Таким образом, факт, что я смог получить вывод 10000 с printf («значение% d», ptr) сам по себе, является UB и просто так он напечатан? – user2001996

+0

@ user2001996: Да, факт, что 'printf (" value% d \ n ", ptr);', казалось, работал, был просто удачей. Если быть точным, это была неудачная удача; крушение скажет вам, что что-то не так. Я добавил немного больше информации к моему ответу. –

1

Нет, определение int *ptr = 10000 не дает неопределенное поведение.

Он преобразует буквальное значение 10000 в указатель и инициализирует ptr с этим значением.

Однако, в вашем примере

int *ptr = 10000; 
printf("value: %d\n", ptr); 
printf("value: %d\n", *ptr); 

оба printf() заявления дают неопределенное поведение.

Первый дает неопределенное поведение, так как формат %d говорит printf(), что соответствующий аргумент типа int, который ptr не является. На практике (с большинством компиляторов/библиотек) он часто с радостью печатает значение 10000, но это случайность. По существу (и немного чрезмерно упрощенно), чтобы это произошло, конверсия в оба конца (например, преобразование 10000 из int в указатель, а затем преобразование этого значения указателя в int) должно давать такое же значение. Выживание в ту же поездку НЕ гарантируется, хотя это происходит с некоторыми реализациями, поэтому первый printf() может ПРИЯТНО хорошо себя вести, несмотря на участие неопределенного поведения.

Часть проблемы с неопределенным поведением заключается в том, что одним из возможных результатов является поведение кода, как ожидает программист. Это не определяет поведение. Это просто означает, что определенный набор обстоятельств (поведение компилятора, операционной системы, аппаратного обеспечения и т. Д.) Позволяет сговориться, чтобы дать поведение, которое кажется разумным программисту.

Второй оператор printf() дает неопределенное поведение, потому что он имеет разности ptr. Стандарт не дает оснований ожидать, что указатель со значением 10000 соответствует чему-либо в частности. Это может быть место в ОЗУ. Это может быть место в видеопамяти. Это может быть значение, которое не соответствует любому местоположению в памяти, которое существует на вашем компьютере. Это может быть логическая или физическая память, которую ваша операционная система считает, что вашему процессу не разрешен доступ (что на самом деле является причиной нарушения доступа в нескольких операционных системах, которые затем отправляют сигнал процессу, на котором запущена ваша программа, направляя ее на завершение).

Многие компиляторы C (при правильной настройке) выдают предупреждение об инициализации ptr, из-за этого - такая инициализация, как это проще для компилятора, обнаружить и обычно указывает на проблемы в последующем коде.

+0

Благодарим вас за другой подробный ответ – user2001996

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