Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   Помогите начинающему понять оператор Си++ (http://forum.oszone.net/showthread.php?t=29390)

Guest 10-10-2004 00:33 203673

Никак не понимаю как работает такая фича, как косвенная модификация.
Вот код:

#include <iostream>
#include <stdlib>

int main(void)
{
  int const var = 1;
  int const* pVar = &var;
  cout << "var = " << var << " *pVar = " << *pVar << endl;

 
  *(int*)pVar = 2;
  cout << "var = " << var << " *pVar = " << *pVar << endl;


  *(int*)&var = 3;
  cout << "var = " << var << " *pVar = " << *pVar << endl;

  system("PAUSE");
  return 0;
}

В результате дает:
var = 1 *pVar = 1
var = 1 *pVar = 2
var = 1 *pVar = 3

Но что это за дела? Это же однин локальный указатель, как он может такое показывать, если в себе содержит просто адрес var?

И, собственно, что значит сам оператор *(int*)pVar = 2;? Вроде похоже на приведение типа, но как-то необычно...
Или вроде pVar приводится к int*, а затем, еще звездочка перед этим всем, чтобы можно было присвоить новое значение переменной на которую он ссылается? Дык переменная не изменяется!
Тогда, *(int*)&var = 3; - ячейки начиная с адреса &var приводятся к типу указателя на int, и эти ячейки затем разиминовываются.

Короче, нифега не понятно. А думать самому лень :-), так что может кто более опытный подскажет что это все такое :-).  
Вопросы такие:
1. Что занчит *(int*)pVar = 2;
2. Что занчит *(int*)&var = 3;
3. И почему, черт возьми, указатель показывает что var равна 3, когда она равна 1??  

ivank 10-10-2004 01:50 203674

Всё очень просто, т.к. переменная var объявлена как константа, то компилятор делает логичное (и, самое главное, законное) предположение, что она не изменяется и всегда равна 1. Производится соответствующая оптимизация (т.е. вместо того что бы обращаться к ячейке памяти и получать заведомую единицу, компилятор сразу кладёт 1 на стек). Почему же под переменную var вообще выделяется память? Да потому, что компилятор видит, что берётся адрес этой переменной, а указателю надо на что-то указывать. Если бы адрес не брался, память можно было бы и не выделять вообще, и это было бы вполне законно.

В то же время, поскольку память под эту константную переменную выделяется. То pVar (и &var) указывает на эту память. Дргое дело, что pVar - указатель на _константу_ и то, на что он указывает изменять нельзя. В вашей программе это обходится сишным приведением типов, которое может снимать константность. Того же можно добиться используя const_cast.

Но! const_cast, так же как и и сишное приведение, является грязным хаком. Поэтому пользоваться им можно только в исключительных случаях.

Попробуйте скомпилировать ваш пример без оптимизации, результат вполне может поменться.

Цитата:

Что занчит *(int*)pVar = 2;
В данном случае то же, что и *const_cast<int*>(pVar) = 2; т.е. с указателя на константу снимается константность, он разименовывается и ячейке памяти, на которую он указывает присваивается 2-ка.

Цитата:

Что занчит *(int*)&var = 3
Почти тоже самое. берётся адрес var (который является указателем на константу) затем происходит всё то же, что описано чуть выше.


А теперь страшное предположение: вам предложил препод эту задачу на сообразительность, посулив лёгкий зачёт или, чем чёрт не шутит, - экзамен автоматом. Вы как тупой студент, который не желает разбираться сам задали этот вопрос здесь.

Почему я так считаю? Просто человек, кторый не знает что такое сишное приведение типов не смог бы написать программу, использующую его. Таково уж моё мнение. Если я ошибся, то готов принести свои извинения. Хотя, сомневаюсь, что мне придётся это делать.

Guest 10-10-2004 03:57 203675

Вроде, понял. Есть две переменные. Та, в памяти, которая оставлена для указателя, и та, которая в стеке, похоже, для ускорения доступа.
Следовательно, если компилить без оптимизации, то переменная будет только одна, и var = 3 *pVar = 3.

===========================================
Я просто первый раз встречаюсь с таким приемом, как снятие константности с помощью сишного привидения типов.

А теперь вроде дошло. Это выражение:
*(int*)pVar = 2;
можно прочесть как привести значение константной переменной, на которую ссылается pVar, к типу int (во время это операции снимается константность) и присвоеть ей единицу. Просто по правилу, в роде надо написать было (int*)*pVar = 2; - это меня и смутило. Почему не записано так? При этом варианте, компилятор пишет,что не может изменить значение константного объекта.


Я думаю, может все дело в этапах. При (int*)*pVar = 2;  варианте в первом этапе идет приведние типа. А потом попытка изменить консанту[ 1. (int*)   2. *pVar = 2;]. А при *(int*)pVar = 2; все идет в один этап. Переменная на которую ссылается указатель, приводится к типу int (потому и звездочка раньше)и сразу изменяется, а уже потом объявляется константой. Я верно предположил???


А теперь действительно страшное предположение :). Я учусь в 11-м классе, и, как говорится, от скуки на все руки. Вот и играюсь с Си++. А Си++ учу сам по книжкам.



Цитата:

Но! const_cast, так же как и и сишное приведение, является грязным хаком.
Если переменная константа - то это не спроста и менять тут ничего не надо. Но, ИМХО, с другой сторону Бьерн Страуструп не от балды вставил в язык оператор const_cast. Значит, есть ситуации, когда он может сильно пригодится.


Guest 10-10-2004 14:02 203676

Ура, все дошло :)!
1. C указателя на константу снимается константность.
2. Он разименовывается.
3. Ячейке памяти, на которую он указывает присваивается 2-ка.

1. (int*)pVar               1. const_cast<int*>(pVar)
2. *(int*)pVar              2. *const_cast<int*>(pVar)
3. *(int*)pVar = 2;         3. *const_cast<int*>(pVar) = 2;

ivank 11-10-2004 18:56 203677

Цитата:

А теперь действительно страшное предположение . Я учусь в 11-м классе, и, как говорится, от скуки на все руки. Вот и играюсь с Си++. А Си++ учу сам по книжкам.
Тогда, извиняюсь. Я C++ примерно тогда же учить начал.

В общем-то, в последнем почте всё правильно написано, так что комментировать больше нечего.


Время: 15:05.

Время: 15:05.
© OSzone.net 2001-