Имя пользователя:
Пароль:  
Помощь | Регистрация | Забыли пароль?  | Правила  

Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » Помогите начинающему понять оператор Си++

Ответить
Настройки темы
Помогите начинающему понять оператор Си++

Аватара для Guest

Guest



Профиль | Цитировать


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

#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??  

Отправлено: 00:33, 10-10-2004

 

редкий гость


Сообщения: 1696
Благодарности: 44

Профиль | Сайт | Отправить PM | Цитировать


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

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

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

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

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

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


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

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

-------
http://ivank.ru


Отправлено: 01:50, 10-10-2004 | #2



Для отключения данного рекламного блока вам необходимо зарегистрироваться или войти с учетной записью социальной сети.

Если же вы забыли свой пароль на форуме, то воспользуйтесь данной ссылкой для восстановления пароля.


Аватара для Guest

Guest


Профиль | Цитировать


Вроде, понял. Есть две переменные. Та, в памяти, которая оставлена для указателя, и та, которая в стеке, похоже, для ускорения доступа.
Следовательно, если компилить без оптимизации, то переменная будет только одна, и 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. Значит, есть ситуации, когда он может сильно пригодится.


Отправлено: 03:57, 10-10-2004 | #3


Аватара для Guest

Guest


Профиль | Цитировать


Ура, все дошло !
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;

Отправлено: 14:02, 10-10-2004 | #4


редкий гость


Сообщения: 1696
Благодарности: 44

Профиль | Сайт | Отправить PM | Цитировать


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

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

-------
http://ivank.ru


Отправлено: 18:56, 11-10-2004 | #5



Компьютерный форум OSzone.net » Программирование, базы данных и автоматизация действий » Программирование и базы данных » Помогите начинающему понять оператор Си++

Участник сейчас на форуме Участник сейчас на форуме Участник вне форума Участник вне форума Автор темы Автор темы Шапка темы Сообщение прикреплено

Похожие темы
Название темы Автор Информация о форуме Ответов Последнее сообщение
Помогите начинающему!!! Kanonir Программное обеспечение Linux и FreeBSD 21 19-03-2007 12:26
Помогите начинающему! xden777 Вебмастеру 4 06-03-2006 16:53
Помогите начинающему curbat Общий по Linux 6 17-05-2004 09:02
Помогите начинающему Guest Общий по Linux 6 05-04-2004 13:41
помогите начинающему Guest Общий по Linux 9 05-03-2004 15:07




 
Переход