Почему в C/C++ не может быть объектов с нулевым адресом ?
От: Forrest_Gump  
Дата: 27.01.04 20:26
Оценка:
Насколько я помню, в DOS по адресу 0000:0000 располагалась таблица векторов прерываний.
То есть ячейка памяти с нулевым адресом — вполне реальный физический объект.

Так почему же

Гарантируется, что нет объектов с нулевым адресом. Следовательно, указатель, равный нулю, можно интерпретировать как указатель, который ни на что не ссылается.

Б.Страуструпп "Язык программирования C++".

Просьба не смеяться
Re: Почему в C/C++ не может быть объектов с нулевым адресом
От: Handler Украина  
Дата: 27.01.04 20:36
Оценка:
Здравствуйте, Forrest_Gump, Вы писали:

F_G>Насколько я помню, в DOS по адресу 0000:0000 располагалась таблица векторов прерываний.

F_G>То есть ячейка памяти с нулевым адресом — вполне реальный физический объект.

F_G>Так почему же

F_G>

F_G>Гарантируется, что нет объектов с нулевым адресом. Следовательно, указатель, равный нулю, можно интерпретировать как указатель, который ни на что не ссылается.

Б.Страуструпп "Язык программирования C++".


F_G>Просьба не смеяться

F_G>

На мой взгляд , проблемма вовсе не в самом языке , а в компиляторе , который настроен на работу
в многозадачной системе , которая в свою очередь , работает в защищенном режиме работы микропроцессора , а в данном режиме , на будущее , нулевой адрес отсутствует , и все попытки обращения по этому адресу вызывают исключение под номером... (извини , не помню). Кстати , подобное исключение очень удобно использовать при отладке приложений : запустил прогу под отладкой и если она глюкнула на этом исключении , значит пишем в память по несуществующему адресу.
Whoa...I did a 'zcat /vmlinuz > /dev/audio' and I think I heard God...
Re[2]: Почему в C/C++ не может быть объектов с нулевым адрес
От: Константин Россия http://flint-inc.ru/
Дата: 27.01.04 21:16
Оценка:
Здравствуйте, Handler, Вы писали:

H>На мой взгляд , проблемма вовсе не в самом языке , а в компиляторе , который настроен на работу

H>в многозадачной системе , которая в свою очередь , работает в защищенном режиме работы микропроцессора , а в данном режиме , на будущее , нулевой адрес отсутствует , и все попытки обращения по этому адресу вызывают исключение под номером... (извини , не помню). Кстати , подобное исключение очень удобно использовать при отладке приложений : запустил прогу под отладкой и если она глюкнула на этом исключении , значит пишем в память по несуществующему адресу.

А в DOS'е как? Это ведь ещё под DOS'ом было так.
Кстати, меня тоже всегда интересовал этот вопрос — почему именно 0, и как вообще можно сделать обозначение невалидного адреса — ведь для любого значения адреса может быть ситуация, что мне потребуется писать именно по этому адресу. Ну или читать на худой конец...
Почему же, ё-моё, ты нигде не пишешь «ё»?
Re: Почему в C/C++ не может быть объектов с нулевым адресом
От: Андрей Тарасевич Беларусь  
Дата: 27.01.04 21:28
Оценка: 6 (2)
Здравствуйте, Forrest_Gump, Вы писали:

F_G>Насколько я помню, в DOS по адресу 0000:0000 располагалась таблица векторов прерываний.

F_G>То есть ячейка памяти с нулевым адресом — вполне реальный физический объект.

F_G>Так почему же

F_G>

F_G>Гарантируется, что нет объектов с нулевым адресом. Следовательно, указатель, равный нулю, можно интерпретировать как указатель, который ни на что не ссылается.

Б.Страуструпп "Язык программирования C++".


F_G>Просьба не смеяться

F_G>

На это вопрос тут уже отвечали не раз. Под "нулевым адресом" в данном случае (в том числе в книге Страуструпа) понимается не машинный (физический) адрес 0, а языковый (логический) нулевой указатель, т.е. указатель, который получается, например, в результате присваивания целочисленной константы 0 (или значения NULL) какому-нибудь указателю. Получившийся в результате такого присваивания указатель может физически указывать не на машинный адрес 0, а в какое-нибудь совсем другое место. В какое — зависит от конкретной платформы.

Если на какой-то платформе машинный адрес 0 не является особым и зарезервированным, то вполне может быть, что присваивание указателю константного целочисленного значения 0 будет приводить к тому, что физически в это указатель будет ложиться, например, 0xFFFFFFFF или что-то в этом роде.

Можешь посмотреть также мои разглагольствования здесь

http://www.rsdn.ru/Forum/Message.aspx?mid=473135&only=1
Автор: Андрей Тарасевич
Дата: 10.12.03
Best regards,
Андрей Тарасевич
Re[2]: Почему в C/C++ не может быть объектов с нулевым адрес
От: Forrest_Gump  
Дата: 27.01.04 22:19
Оценка:
Здравствуйте, Андрей Тарасевич, Вы писали:
АТ>Можешь посмотреть также мои разглагольствования здесь
АТ>http://www.rsdn.ru/Forum/Message.aspx?mid=473135&only=1
Автор: Андрей Тарасевич
Дата: 10.12.03

Спасибо, прочёл.
Ты пишешь:

Null-pointer value of type 'T*' — это "физический ноль", это конкретное физическое значение null-указателя данного типа 'T*' на данной платформе. Это то значение, которое физически ложится в указатель, когда ты на уровне С/С++ кода присваиваешь этому указателю литеральный 0. Это может быть и '0x00000000', и '0x12345678', и '0xBAADF00D'. Это значение в общем случае зависит от платформы. Более того, оно даже может зависеть от конкретного типа 'T*'.


А можно ли просвоить указателю что-то, чтобы при генерации кода его значение заведомо было равно 0x00000000 ?
Хотя бы для того, чтобы из-под ДОСа обратиться к началу физической памяти.
(Наверное, можно , только как ?)
Re[2]: Почему в C/C++ не может быть объектов с нулевым адрес
От: Кодт Россия  
Дата: 27.01.04 22:54
Оценка: 7 (2)
Здравствуйте, Handler, Вы писали:

F_G>>Насколько я помню, в DOS по адресу 0000:0000 располагалась таблица векторов прерываний.

F_G>>То есть ячейка памяти с нулевым адресом — вполне реальный физический объект.

F_G>>Так почему же

F_G>>

F_G>>Гарантируется, что нет объектов с нулевым адресом. Следовательно, указатель, равный нулю, можно интерпретировать как указатель, который ни на что не ссылается.

Б.Страуструпп "Язык программирования C++".


H>На мой взгляд , проблемма вовсе не в самом языке , а в компиляторе , который настроен на работу

H>в многозадачной системе , которая в свою очередь , работает в защищенном режиме работы микропроцессора , а в данном режиме , на будущее , нулевой адрес отсутствует , и все попытки обращения по этому адресу вызывают исключение под номером... (извини , не помню). Кстати , подобное исключение очень удобно использовать при отладке приложений : запустил прогу под отладкой и если она глюкнула на этом исключении , значит пишем в память по несуществующему адресу.

Нет, тут дело именно в языке.
Указатель — это логическая, а не физическая величина. Только с точки зрения удобства формат данных в указателе совпадает с форматом адресных регистров.
При этом логический 0-указатель вовсе необязательно представлен как "все биты — нули". Это исключительно вопрос договорённости.

Адресное пространство программы на С++ — это подпространство всей адресуемой памяти. Указатели могут быть либо "логическим нулём", либо адресами действительных объектов, либо адресами "за концом объекта". Если ячейка 0x00000000 не содержит С++ных данных, указатель на неё не существует (разве что ошибочный или нулевой). Если 0x00000000 доступна — тогда физическое представление нулевого указателя должно быть другим, например, 0xFFFFFFFF или 0xCDCDCDCD.
То есть принципиально лишь, что нулевой указатель отличен от других.

Кстати, раз уж заговорили о таблице прерываний и прочих служебных данных.
В защищённом режиме эти данные лежат вне адресного пространства процесса. Хочешь к ним обратиться — потанцуй с бубном на ассемблере. По аналогии с аппаратными портами — хотя у каждого порта есть адрес на шине, но обратиться к ним можно либо на ассемблере, либо вызовом функции, которая сама написана на ассемблере.

Наконец, по поводу аппаратных исключений в виндах.
Это сделано только для отладочных целей. Поскольку разыменование указателя, не указывающего на данные (т.е. нулевой указатель, указатели за конец объектов, инвалидные указатели) — это неопределённое поведение, то первая страница — 0x00000000-0x00001000 (кажется, так) — это ловушка: запрещено не только писать, но и читать её. Ведь помимо нулевого адреса, легко получить и близкие к нулю (например, второй элемент массива по нулевому указателю).
Виртуальной памяти много, поэтому мы можем выкинуть 4 килобайта из адресного пространства и не шибко расстроиться.
... << RSDN@Home 1.1.0 stable >>
Перекуём баги на фичи!
Re[3]: Почему в C/C++ не может быть объектов с нулевым адрес
От: Шахтер Интернет  
Дата: 28.01.04 02:05
Оценка:
Здравствуйте, Forrest_Gump, Вы писали:

F_G>А можно ли просвоить указателю что-то, чтобы при генерации кода его значение заведомо было равно 0x00000000 ?

F_G>Хотя бы для того, чтобы из-под ДОСа обратиться к началу физической памяти.
F_G>(Наверное, можно , только как ?)

Какие проблемы -- под DOS м то. Нулем и инициализируй. Только указатель нужен дальний.
Что касается исходного вопроса -- речь не идёт об аппаратных гарантиях. Речь у Страуструпа идёт о том, что в языке нет легальных способов создать объект с нулевым адресом. Хотя с помощью грязного хака это сделать можно в некоторых случаях.
... << RSDN@Home 1.1.0 stable >>
В XXI век с CCore.
Копай Нео, копай -- летать научишься. © Matrix. Парадоксы
Re[3]: Почему в C/C++ не может быть объектов с нулевым адрес
От: Аноним  
Дата: 28.01.04 07:47
Оценка:
F_G>А можно ли просвоить указателю что-то, чтобы при генерации кода его значение заведомо было равно 0x00000000 ?
F_G>Хотя бы для того, чтобы из-под ДОСа обратиться к началу физической памяти.
F_G>(Наверное, можно , только как ?)

void *p;
memset(&p, 0, sizeof(p));

Подойдёт?

Обычно можно привести к указателю какое-нибудь целое подходящего размера и присвоить его указателю.

long z = 0;
void *p = (void *)z;
// void *p = (void *)0;
//- не прокатит, поскольку литерал 0 при при преобразовании в указатель может перестать
// быть всеми нулями, что мы и пытаемся обойти
// не проверял, но должно сработать.

Ещё можно заюзать reinterpret_cast<void*>, запихать указатель в union с чем-нибудь, что хорошо обнуляется.

Но всё это теряет смысл, если модель памяти не плоская (дескриптор сегмента:смещение), поскольку дескриптор из всех нулей может и не существовать.
Re[3]: Почему в C/C++ не может быть объектов с нулевым адрес
От: Аноним  
Дата: 28.01.04 08:01
Оценка: 2 (1)
F_G>А можно ли просвоить указателю что-то, чтобы при генерации кода его значение заведомо было равно 0x00000000 ?
F_G>Хотя бы для того, чтобы из-под ДОСа обратиться к началу физической памяти.
F_G>(Наверное, можно , только как ?)

Можно, конечно, но только указатель должен быть far или huge, но дело не в этом. ДОС — не та ОСь на которую следует ориентироваться. В ДОСе (в реальном режиме) существуют только физические адреса, в то время как в Виндоусе и в разных версиях Юникса (да и во всех современных ОСях) каждый процесс имеет свое адресное пространство. Другими словами, логические (или виртуальные) адреса программы не совпадают с физическими ячейками памяти. Например, используя 32-разрядные регистры, каждый процесс может использовать СВОИ СОБСТВЕННЫЕ виртуальные адреса от 0 до 2^32 — 1. То есть, если один процесс считывает данные по адресу 44FAAFFC, то он считывает только свои данные, и данные другого процесса по адресу 44FAAFFC не имеют ничего общего с данными первого процесса. В процессе загрузки программы, ОСь создает структуры данных, описывающие где в памяти (или на диске) находятся части программы (они могут быть разбросаны по физической памяти), и основываясь на этих структурах данных (или таблицах), микропроцессор отображает виртуальные адреса процесса в физические. Таким образом, если виртуальные адреса данных и кода находятся начиная с какого-то адреса, то можно условиться что какой-то из виртуальных адресов ниже данного адреса может служить нулевым указателем.

Одна из целей современных ОСей — запретить несанкционированный доступ по физическим адресам (как раз то, что ты хочешь сделать в ДОСе, обратившись к таблице векторов прерываний). Для чего это делается? Это делается для того, чтобы никакой процесс не смог испортить данные чужого процесса и самого ядра. Отсюда и название — защищенный режим процессора.

Это, конечно же, все упрощенно, но принцип таков и очень даже гениален.
Re[2]: Почему в C/C++ не может быть объектов с нулевым адрес
От: SWW Россия  
Дата: 28.01.04 08:10
Оценка:
АТ>Если на какой-то платформе машинный адрес 0 не является особым и зарезервированным, то вполне может быть, что присваивание указателю константного целочисленного значения 0 будет приводить к тому, что физически в это указатель будет ложиться, например, 0xFFFFFFFF или что-то в этом роде.

Хм, а как на такой платформе записать в указатель нулевое значение чтобы с ним работать, ведь оно там будет валидным?
Re[3]: Почему в C/C++ не может быть объектов с нулевым адрес
От: Кодт Россия  
Дата: 28.01.04 09:06
Оценка:
Здравствуйте, SWW, Вы писали:


АТ>>Если на какой-то платформе машинный адрес 0 не является особым и зарезервированным, то вполне может быть, что присваивание указателю константного целочисленного значения 0 будет приводить к тому, что физически в это указатель будет ложиться, например, 0xFFFFFFFF или что-то в этом роде.


SWW>Хм, а как на такой платформе записать в указатель нулевое значение чтобы с ним работать, ведь оно там будет валидным?


Указателю можно присваивать только валидные значения указателей — константу 0, адреса объектов и арифметические выражения над указателями.

Запись в указатель явно указанного машинного адреса — это хак.
Если ячейка 0x00000000 доступна, то компилятор должен
assert(sizeof(char*)==sizeof(long)); // условие для успешного реинтерпреткаста
char* pc = reinterpret_cast<char*>(0L);
char* pn = 0;
assert(pc != pn);

Другое дело, что доступная нулевая ячейка — это экзотика (для прикладного программирования).
Перекуём баги на фичи!
Re[3]: Почему в C/C++ не может быть объектов с нулевым адрес
От: konst  
Дата: 28.01.04 13:30
Оценка:
Здравствуйте, Forrest_Gump, Вы писали:

F_G>А можно ли просвоить указателю что-то, чтобы при генерации кода его значение заведомо было равно 0x00000000 ?

F_G>Хотя бы для того, чтобы из-под ДОСа обратиться к началу физической памяти.
F_G>(Наверное, можно , только как ?)

Под виндами безо всяких хаков:
class A
{
public:
  A() {}
  int foo(int a) { return a*5; }
};

int _tmain(int argc, _TCHAR* argv[])
{
  A* pA = new((void*)0) A;
  printf("pA->foo(5) == %d\n", pA->foo(5));
  delete pA;
  getchar();
    return 0;
}

отлично работает
Re[4]: Почему в C/C++ не может быть объектов с нулевым адрес
От: konst  
Дата: 28.01.04 13:37
Оценка:
Но! Под виндами, естественно, так данных-мемберов нельзя использовать, а вот под досом выйдет.
Вот тоже непонятка в студии 7.1

так работает
class A
{
public:
  A(): abc(15) {}
  int foo(int a) { return a*5; }
private:
  int abc;
};

int _tmain(int argc, _TCHAR* argv[])
{
  A* pA = new((void*)0) A;
  printf("pA->foo(5) == %d\n", pA->foo(5));
  delete pA;
  getchar();
    return 0;
}


конечно падает при вызове pA->foo(5) с акцес вайолейшн при чтении по нулю:
class A
{
public:
  A(): abc(15) {}
  int foo(int a) { return a*abc; }
private:
  int abc;
};
// остальное без изменений
Re[4]: Почему в C/C++ не может быть объектов с нулевым адрес
От: Павел Кузнецов  
Дата: 28.01.04 13:42
Оценка:
Здравствуйте, konst, Вы писали:

k> Под виндами безо всяких хаков:

k>
 k>   A* pA = new((void*)0) A;
 k>


Вот это и есть один из возможных "хаков".
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[5]: Почему в C/C++ не может быть объектов с нулевым адрес
От: konst  
Дата: 28.01.04 14:21
Оценка:
Здравствуйте, Павел Кузнецов, Вы писали:
ПК>Вот это и есть один из возможных "хаков".
Спорить не хочется, однако почему 0 для физического адреса Вы хаком считаете? А 0x975A60 уже было бы не хаком?
Re: Почему в C/C++ не может быть объектов с нулевым адресом
От: PK Sly http://www.vocord.ru/
Дата: 28.01.04 14:43
Оценка:
Здравствуйте, Forrest_Gump, Вы писали:

F_G>Насколько я помню, в DOS по адресу 0000:0000 располагалась таблица векторов прерываний.

F_G>То есть ячейка памяти с нулевым адресом — вполне реальный физический объект.

F_G>Так почему же

F_G>

F_G>Гарантируется, что нет объектов с нулевым адресом. Следовательно, указатель, равный нулю, можно интерпретировать как указатель, который ни на что не ссылается.

Б.Страуструпп "Язык программирования C++".


Потому же, почему в строке, представленной char* не может быть символа '\0'.
Просто так договорились. Но при этом никто не мешает работать с таким указателем как с действительным.
VAX/VMS rulez!
Re[2]: Почему в C/C++ не может быть объектов с нулевым адрес
От: Павел Кузнецов  
Дата: 28.01.04 14:57
Оценка:
Здравствуйте, PK, Вы писали:

PS> Потому же, почему в строке, представленной char* не может быть символа '\0'.


В строке "представленной char*" символ '\0' вполне может быть. И не один.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: Почему в C/C++ не может быть объектов с нулевым адрес
От: Павел Кузнецов  
Дата: 28.01.04 15:08
Оценка:
Здравствуйте, konst, Вы писали:

ПК>> Вот это и есть один из возможных "хаков".


k> Спорить не хочется, однако почему 0 для физического адреса

k> Вы хаком считаете?

Потому что:
1) по адресу 0 нет storage;
2) стандарт явно говорит, что по адресу 0 не может существовать никакой объект.

k> А 0x975A60 уже было бы не хаком?


Тем более было бы "хаком": 0x975A60, вообще, не является валидным указателем.
Posted via RSDN NNTP Server 1.7 "Bedlam"
Легче одурачить людей, чем убедить их в том, что они одурачены. — Марк Твен
Re[6]: Почему в C/C++ не может быть объектов с нулевым адрес
От: jazzer Россия Skype: enerjazzer
Дата: 28.01.04 15:10
Оценка:
Здравствуйте, konst, Вы писали:

K>Здравствуйте, Павел Кузнецов, Вы писали:

ПК>>Вот это и есть один из возможных "хаков".
K>Спорить не хочется, однако почему 0 для физического адреса Вы хаком считаете? А 0x975A60 уже было бы не хаком?

Конечно же, хаком.
Попробуй потом откомпилировать такую прогу на другой платформе.
jazzer (Skype: enerjazzer) Ночная тема для RSDN
Автор: jazzer
Дата: 26.11.09

You will always get what you always got
  If you always do  what you always did
Re[3]: Почему в C/C++ не может быть объектов с нулевым адрес
От: Andrew S Россия http://alchemy-lab.com
Дата: 28.01.04 16:27
Оценка:
К>Наконец, по поводу аппаратных исключений в виндах.
К>Это сделано только для отладочных целей. Поскольку разыменование указателя, не указывающего на данные (т.е. нулевой указатель, указатели за конец объектов, инвалидные указатели) — это неопределённое поведение, то первая страница — 0x00000000-0x00001000 (кажется, так) — это ловушка: запрещено не только писать, но и читать её. Ведь помимо нулевого адреса, легко получить и близкие к нулю (например, второй элемент массива по нулевому указателю).
К>Виртуальной памяти много, поэтому мы можем выкинуть 4 килобайта из адресного пространства и не шибко расстроиться.

Не 4, а 64 кб (10000h). Более того, еще есть верхний предохранительный блок (ниже 3-го гигабайта адресного пространства) — тоже 64 кб + защитные страницы (анти) переполнения стека для каждого треда (еще по 4-128 кб).
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.