Здравствуйте, abrarov, Вы писали:
A>Может хватит "высасывать из пальца" проблему? A>e == 'a' это A>1) по всем правилам C++ A>2) проверено Visual C++ 10.0
По всем правилам С++ эта программа может делать всё, что угодно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Edain, Вы писали:
E>...но это будет _не_ обязательно адрес переменной b, т.к. никто не гарантирует, что a и b будут в памяти расположены последовательно (или гарантирует?).
Для начала, никто не гарантирует, не только размещение переменной b в памяти, а не где-то ещё, в регистрах, например, или ещё где, так и вообще её существования...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
N> char a = 'a';
N> char b = 'b';
N> char c;
N> char d;
N> char e;
N> char* ptr = &a;
N> c = *ptr++;
N> d = *ptr--;
N>
N>После выполнения указаных действий c равно значению а, а d — указывают на пустую область памяти. Почему?
c будет иметь значение 'a', потому что сначала происходит разыменование, а потом инкремент (т.к. оператор ++ постфиксный). При этом ptr будет указывать на ячейку памяти, расположенную сразу за переменной a (&a + sizeof(char)), но это будет _не_ обязательно адрес переменной b, т.к. никто не гарантирует, что a и b будут в памяти расположены последовательно (или гарантирует?). Поэтому когда выполняется d = *ptr--, переменная d получает в качестве значения мусор, хранящийся по адресу &a + sizeof(char), а указатель вновь будет указывать на a.
achp:
E>>(&a + sizeof(char))
A>С точки зрения формальной начиная с этого момента мы имеем неопределённое поведение, так как адресная арифметика дозволяется только над указателями, указывающими на элемент массива; &a не указывает на элемент массива.
Здесь как раз-таки всё законно:
C99 — 6.5.6 Additive operators — p.7:
For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
C++03 — 5.7 Additive operators — p.4:
For the purposes of these operators, a pointer to a nonarray object behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
Здравствуйте, abrarov, Вы писали:
A>Можно подробнее? Или у меня просто с юмором туго? Словосочетание "правила C++", кончено, режет слух.
char a = 'a';
char b = 'b';
char c;
char d;
char e;
char* ptr = &a;
c = *ptr++;
d = *ptr--;
e = *ptr;
Выделенная строчка содержит разыменование недействительного указателя, что приводит к неопределённому поведению. Стандарт языка не предъявляет никаких требований к поведению программы, содержащей неопределённое поведение.
На практике эта строчка может «снести крышу» оптимизирующему компилятору.
Здравствуйте, abrarov, Вы писали:
A>Можно подробнее? Или у меня просто с юмором туго? Словосочетание "правила C++", кончено, режет слух.
Там вроде как разименование невалидного указателя. Это UB дальше может быть что угодно...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, achp, Вы писали:
A>Здравствуйте, abrarov, Вы писали:
A>>Можно подробнее? Или у меня просто с юмором туго? Словосочетание "правила C++", кончено, режет слух.
A>
A>char a = 'a';
A>char b = 'b';
A>char c;
A>char d;
A>char e;
A>char* ptr = &a;
A>c = *ptr++;
A>d = *ptr--;
A>e = *ptr;
A>
A>Выделенная строчка содержит разыменование недействительного указателя, что приводит к неопределённому поведению. Стандарт языка не предъявляет никаких требований к поведению программы, содержащей неопределённое поведение.
A>На практике эта строчка может «снести крышу» оптимизирующему компилятору.
О, наконец-то дошло. Спасибо и achp, и Erop. Дальше UB будет только UB
Programs must be written for people to read, and only incidentally for machines to execute
Здравствуйте, abrarov, Вы писали: A>На рабочем мониторе (только что) едва заметил выделенную строку. Да, в d будет "мусор" (UB). Но программа (в общем случае — указатель не выходит за пределы readable памяти) не должна упасть и компилятору "наплевать" на такие выкрутасы. Я же писал про значение переменной e.
Этого никто не гарантирует.
Во-первых, бывают интерпретаторы С++
Во-вторых, на некоторых RISK архитектурах бывают такие диапазоны адресов, которые читаются/пишутся быстрее. Фактически, это просто массивы отображённых на память регистров. И компилятор может разместить переменную а там, ну и когда ты попробуешь взять адрес соседней с а ячейки, сможешь попасть в границу чего угодно, в том числе и readable памяти...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Edain, Вы писали:
E>(&a + sizeof(char))
С точки зрения формальной начиная с этого момента мы имеем неопределённое поведение, так как адресная арифметика дозволяется только над указателями, указывающими на элемент массива; &a не указывает на элемент массива.
Если какой-нибудь ретивый компилятор наоптимизирует что-то таким образом, что (c != a), то будет в полном праве так поступить.
Здравствуйте, achp, Вы писали:
A>Здравствуйте, Edain, Вы писали:
E>>(&a + sizeof(char))
A>С точки зрения формальной начиная с этого момента мы имеем неопределённое поведение, так как адресная арифметика дозволяется только над указателями, указывающими на элемент массива; &a не указывает на элемент массива.
A>Если какой-нибудь ретивый компилятор наоптимизирует что-то таким образом, что (c != a), то будет в полном праве так поступить.
Тогда почему после ввода переменной типа char e;
и присвоения e *ptr; (уже после выполнения инкрементирования и декремента)
е тоже будет указывать на мусор в памяти?
Здравствуйте, Nortsx, Вы писали:
N>Тогда почему после ввода переменной типа char e; N>и присвоения e *ptr; (уже после выполнения инкрементирования и декремента) N>е тоже будет указывать на мусор в памяти?
Можно уточнить вопрос и конкретизировать его фрагментом кода?
Здравствуйте, Nortsx, Вы писали: N>После выполнения указаных действий c равно значению а, а d — указывают на пустую область памяти. Почему?
char a = 'a';
char b = 'b';
char c;
char d;
char e;
char* ptr = &a;
c = *ptr++; // выражение ptr++ - это пост-инкремент. Поэтому *(ptr++) даст 'a'.
d = *ptr--; // здесь уже ptr указывает на то, что лежало в стеке до того, как в стек была помещена переменная a
// (на x86 стек растет в сторону меньших адресов). Т.к. ptr-- тоже пост-инкремент, то
// d будет указывать как раз таки на то самое, что было "положено" в стек, до появления переменной a.
Вообще пост-инкремент (и пре-инкремент) очень коварный. Рекомендую почитать про точки следования (C++ sequence point). Например, вот здесь.
Programs must be written for people to read, and only incidentally for machines to execute
Здравствуйте, achp, Вы писали:
A>Здравствуйте, Nortsx, Вы писали:
N>>Тогда почему после ввода переменной типа char e; N>>и присвоения e *ptr; (уже после выполнения инкрементирования и декремента) N>>е тоже будет указывать на мусор в памяти?
A>Можно уточнить вопрос и конкретизировать его фрагментом кода?
Конкретизирую)
char a = 'a';
char b = 'b';
char c;
char d;
char e;
char* ptr = &a;
c = *ptr++;
d = *ptr--;
e = *ptr;
Здравствуйте, Nortsx, Вы писали:
N>Здравствуйте, achp, Вы писали:
A>>Здравствуйте, Edain, Вы писали:
E>>>(&a + sizeof(char))
A>>С точки зрения формальной начиная с этого момента мы имеем неопределённое поведение, так как адресная арифметика дозволяется только над указателями, указывающими на элемент массива; &a не указывает на элемент массива.
A>>Если какой-нибудь ретивый компилятор наоптимизирует что-то таким образом, что (c != a), то будет в полном праве так поступить.
N>Тогда почему после ввода переменной типа char e; N>и присвоения e *ptr; (уже после выполнения инкрементирования и декремента) N>е тоже будет указывать на мусор в памяти?
Ну не совсем мусор.
#include <stdio.h>
int main(int argc, char* argv[])
{
char a = 'a';
char b = 'b';
int c;
int d;
int e;
char* ptr = &a;
c = *ptr++;
d = *ptr--;
printf("c:%d\nd:%d", c, d);
}
D:\dev\prj\test>hz
c:97
d:-96
#include <stdio.h>
int main(int argc, char* argv[])
{
char a = 'a';
char b = 'b';
int c;
int d;
int e;
char* ptr = &b;
c = *ptr++;
d = *ptr--;
printf("c:%d\nd:%d", c, d);
}
Что означает зщапись например int& i = какому нить другмоу инту.
Это ссылка, но какую функциональность может она нести, если для взятия ссылки от объекта достаточно &имя.
Вот правда не понимаю
Здравствуйте, Masterkent, Вы писали:
E>>>(&a + sizeof(char))
A>>С точки зрения формальной начиная с этого момента мы имеем неопределённое поведение, так как адресная арифметика дозволяется только над указателями, указывающими на элемент массива; &a не указывает на элемент массива.
M>Здесь как раз-таки всё законно:
Хм, действительно. Интересно, зачем такое безобразие сделано…
Здравствуйте, Nortsx, Вы писали:
N>Что означает зщапись например int& i = какому нить другмоу инту. N>Это ссылка, но какую функциональность может она нести, если для взятия ссылки от объекта достаточно &имя. N>Вот правда не понимаю
Почему нужно спрашивать на форуме то, что прописано в любом учебнике?
Здравствуйте, achp, Вы писали:
A>Здравствуйте, Nortsx, Вы писали:
N>>Что означает зщапись например int& i = какому нить другмоу инту. N>>Это ссылка, но какую функциональность может она нести, если для взятия ссылки от объекта достаточно &имя. N>>Вот правда не понимаю
A>Почему нужно спрашивать на форуме то, что прописано в любом учебнике?
Если найдете цитату из страуструпа или откуда то еще где написано
int& i отличается от &имя переменной тем то и тем то, то... ну вы понимаете
Здравствуйте, abrarov, Вы писали:
A>Здравствуйте, Nortsx, Вы писали:
N>>>>
N>>>> char a = 'a';
N>>>> char b = 'b';
N>>>> char c;
N>>>> char d;
N>>>> char e;
N>>>> char* ptr = &a;
N>>>> c = *ptr++;
N>>>> d = *ptr--;
N>>>> e = *ptr;
N>>>>
A>>>И что? Что-то поменялось? N>>e = неясно чему. Вот в чем проблема. N>>Проверял виндовым компилятором.
A>Может хватит "высасывать из пальца" проблему? A>e == 'a' это A>1) по всем правилам C++ A>2) проверено Visual C++ 10.0
Проверил сегондя еще раз — теперь все оп правилам с++. ящитаю я наконец то освоился и тему можно закрывать. Спасибо за желание помочь нубу)
Здравствуйте, Erop, Вы писали:
E>Здравствуйте, abrarov, Вы писали: A>>Можно подробнее? Или у меня просто с юмором туго? Словосочетание "правила C++", кончено, режет слух. E>Там вроде как разименование невалидного указателя. Это UB дальше может быть что угодно...
Что-то не пойму, почему указатель перестал быть валидным? От того, что его сначала инкрементировали, а затем декрементировали, что-то изменилось? Становится интересно. Можно привести ссылку на соотв. пункт в стандарте?
Уже взятие адреса переменной a и дальнейшая работа с указателем ptr, я полагаю, должна заставить оптимизирующий компилятор расположить переменную a в стеке (а не пытаться "схитрить" с регистрами).
Или тут что-то с "коварным" aliasing/strict aliasing?
Programs must be written for people to read, and only incidentally for machines to execute
> С точки зрения формальной начиная с этого момента мы имеем неопределённое поведение, > так как адресная арифметика дозволяется только над указателями, указывающими на элемент массива; > &a не указывает на элемент массива.
Так? Что-то не найду этого в стандарте.
Programs must be written for people to read, and only incidentally for machines to execute
For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
C++03 — 5.7 Additive operators — p.4:
For the purposes of these operators, a pointer to a nonarray object behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
Значит, я все таки прав и e == 'a' ?
Programs must be written for people to read, and only incidentally for machines to execute
A>char a = 'a';
A>char b = 'b';
A>char c;
A>char d;
A>char e;
A>char* ptr = &a;
A>c = *ptr++;
A>d = *ptr--;
A>e = *ptr;
A>
A>Выделенная строчка содержит разыменование недействительного указателя, что приводит к неопределённому поведению. Стандарт языка не предъявляет никаких требований к поведению программы, содержащей неопределённое поведение. A>На практике эта строчка может «снести крышу» оптимизирующему компилятору.
На рабочем мониторе (только что) едва заметил выделенную строку. Да, в d будет "мусор" (UB). Но программа (в общем случае — указатель не выходит за пределы readable памяти) не должна упасть и компилятору "наплевать" на такие выкрутасы. Я же писал про значение переменной e.
Programs must be written for people to read, and only incidentally for machines to execute
Здравствуйте, abrarov, Вы писали:
A>Что-то не пойму, почему указатель перестал быть валидным? От того, что его сначала инкрементировали, а затем декрементировали, что-то изменилось? Становится интересно. Можно привести ссылку на соотв. пункт в стандарте?
Взяли указатель на скаляр
Сделали ему *, потом ++
Пока что всё хорошо.
Но потом ему сделали * и --, то есть разыменовали указатель в никуда...
A>Уже взятие адреса переменной a и дальнейшая работа с указателем ptr, я полагаю, должна заставить оптимизирующий компилятор расположить переменную a в стеке (а не пытаться "схитрить" с регистрами).
Не должна. Компилятор может положить на какое-то время переменную в стек, а потом опять поднять в регистр...
A>Или тут что-то с "коварным" aliasing/strict aliasing?
И с ним тоже.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, achp, Вы писали:
A>Здравствуйте, abrarov, Вы писали:
A>>Можно подробнее? Или у меня просто с юмором туго? Словосочетание "правила C++", кончено, режет слух.
A>
A>char a = 'a';
A>char b = 'b';
A>char c;
A>char d;
A>char e;
A>char* ptr = &a;
A>c = *ptr++;
A>d = *ptr--;
A>e = *ptr;
A>
A>Выделенная строчка содержит разыменование недействительного указателя, что приводит к неопределённому поведению. Стандарт языка не предъявляет никаких требований к поведению программы, содержащей неопределённое поведение.
A>На практике эта строчка может «снести крышу» оптимизирующему компилятору.
Тут я немного не понял, почему указатель стал недействительным. Указатель — это переменная, которая хранит адрес. Сначала он хранил адрес переменной a, поэтому значение ptr было корректным. После инкремента указателя адрес по-прежнему корректен (значение переменной ptr изменилось на размер типа char в большую сторону). А что лежит по этому адресу, указателю без разницы. Он честно вернет значение ячейки памяти, на которую указывает. Откуда берется UB?
Здравствуйте, Nortsx, Вы писали:
N>Что означает зщапись например int& i = какому нить другмоу инту. N>Это ссылка, но какую функциональность может она нести, если для взятия ссылки от объекта достаточно &имя. N>Вот правда не понимаю
Ссылки полезно использовать в качестве формальных аргументов функций, чтобы избежать копирования этих самых аргументов. Также я иногда использую ссылки в циклах по контейнерам исключительно в эстетических целях, чтобы не использовать итераторы. Например,
for (std::vector<MyFancyObject>::iterator i = _objects.begin(), iend = _objects.end(); i != iend; ++i)
{
MyFancyObject &obj = *i;
DoStuffWithObject(obj);
}
Не знаю, насколько это снижает производительность цикла, не мерял.
А вообще, да, это базовые вещи, которые отлично разъяснены во всех учебниках.
E>Тут я немного не понял, почему указатель стал недействительным. Указатель — это переменная, которая хранит адрес. Сначала он хранил адрес переменной a, поэтому значение ptr было корректным. После инкремента указателя адрес по-прежнему корректен (значение переменной ptr изменилось на размер типа char в большую сторону). А что лежит по этому адресу, указателю без разницы. Он честно вернет значение ячейки памяти, на которую указывает. Откуда берется UB?
Во-первых, этот указатель всё ещё корректен, только ещё раз его инкрементировать нельзя
Во-вторых, тут UB будет при попытке разименования этого указателя.
Ну и, в-третьих, если по-честному смотреть, то использовать в качестве указателя всякий мусор тоже нельзя. Даже присваивать, а не то, что разименовывать. Тут есть всякие флеймы, по поводу навелидных указателей. Поищи.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Edain, Вы писали:
E>Здравствуйте, Nortsx, Вы писали:
N>>Что означает зщапись например int& i = какому нить другмоу инту. N>>Это ссылка, но какую функциональность может она нести, если для взятия ссылки от объекта достаточно &имя. N>>Вот правда не понимаю
E>Ссылки полезно использовать в качестве формальных аргументов функций, чтобы избежать копирования этих самых аргументов. Также я иногда использую ссылки в циклах по контейнерам исключительно в эстетических целях, чтобы не использовать итераторы. Например,
E>
Здравствуйте, Nortsx, Вы писали:
N>Здравствуйте, Edain, Вы писали:
E>>Здравствуйте, Nortsx, Вы писали:
N>>>Что означает зщапись например int& i = какому нить другмоу инту. N>>>Это ссылка, но какую функциональность может она нести, если для взятия ссылки от объекта достаточно &имя. N>>>Вот правда не понимаю
E>>Ссылки полезно использовать в качестве формальных аргументов функций, чтобы избежать копирования этих самых аргументов. Также я иногда использую ссылки в циклах по контейнерам исключительно в эстетических целях, чтобы не использовать итераторы. Например,
E>>
E>>Не знаю, насколько это снижает производительность цикла, не мерял.
E>>А вообще, да, это базовые вещи, которые отлично разъяснены во всех учебниках.
Сорри,отправил пустое сообщение.
Как раз такой вопрос у меня и возник после прочтения учебника)
Он звучит не как "зачем нужны ссылки", а как "зачем ссылкам псевдонимы".
Ну я жуе увидел примеры использования, когда улучшается ридабилити кода и т д.
N> char a = 'a';
N> char b = 'b';
N> char c;
N> char d;
N> char e;
N> char* ptr = &a;
N> c = *ptr++;
N> d = *ptr--;
N>
N>После выполнения указаных действий c равно значению а, а d — указывают на пустую область памяти. Почему?
У меня два варианта:
1) компилятор выделяет каждой переменной два байта,- т.е. выравнивает на границу слова.
2) компилятор оптимизирует код и не выделяет переменным память
On 01/26/2012 02:17 PM, wisp wrote:
> N> char a = 'a'; > N> char b = 'b'; > N> char c; > N> char d; > N> char e; > N> char* ptr =&a; > N> c = *ptr++; > N> d = *ptr--; > N> > > > > N>После выполнения указаных действий c равно значению а, а d — указывают на > пустую область памяти. Почему?
d -- char d;, он никуда указывать не может.
> У меня два варианта: > 1) компилятор выделяет каждой переменной два байта,- т.е. выравнивает на границу > слова.
Это может быть, но это -- проблемы компилятора.
А твоего кода пролемы, что в этой строке:
d = *ptr--;
ты адресуешся по адресу несуществующей переменной.
> 2) компилятор оптимизирует код и не выделяет переменным память
Тут нет никаких выделений памяти и без оптимизации.
Здравствуйте, MasterZiv, Вы писали:
>> N> char a = 'a'; >> N> char b = 'b'; >> N> char d; >> N> char e; >> N> char* ptr =&a; >> N> c = *ptr++; >> N> d = *ptr--; >> N>
MZ>d = *ptr--; MZ>ты адресуешся по адресу несуществующей переменной.
Насколько я понял просмотрев весь тред: >> N> char* ptr =&a; >> N> c = *ptr++;
начиная с этого момента в ptr лежит адрес произвольного куска памяти, и если убрать разыменование и просто сделать ptr--, то в дальнейшем какие либо операции по нему будут по прежнему операциями с другим произвольным куском памяти, пусть и отстоящим от него на sizeof(char *).
Уточните новичку — я написал верное резюме по мотивам этого треда? ?-)
PS: Сильно напоминает измерения в ядерной физике в которых постулируют невозможность поиметь сразу и координату и энергию, хотя из того, что вот тут накрутили вокруг квантовых компов: http://www.membrana.ru/particle/1901 вывод можно сделать и такой: эти "квантовые" штуки по сути всего лишь очередной сферический конь в вакууме очень удобный для расчетов, господь бог же не подкидывает монетку желая узнать всё что можно о энергии и координате частицы. =)
N> char a = 'a';
N> char b = 'b';
N> char c;
N> char d;
N> char e;
N> char* ptr = &a;
N> c = *ptr++;
N> d = *ptr--;
N>
N>После выполнения указаных действий c равно значению а, а d — указывают на пустую область памяти. Почему?
Потому что компилятор не обязан размещать переменные подряд, сплошь и вверх по стеку.
Только одна переменная — a — обязана иметь адрес и размещаться физически на стеке (т.к. её адрес взяли, ptr=&a).
Другая переменная — d — обязана размещаться где угодно как неконстантная (поскольку ей присваивается нечто произвольное, *(&a+1)).
Переменные b и c можно заменить на константы ('b' и 'a' соответственно) и проинлайнить. Это если компилятор оптимизирующий.
А если не оптимизирующий, и честно размещает переменные на стеке, и не выравнивает их на границу машинного слова (это могло бы повысить скорость доступа), то... ВНЕЗАПНО! Стек-то у нас растёт вниз. http://ideone.com/GlgNG
Здравствуйте, achp, Вы писали:
E>>(&a + sizeof(char))
A>С точки зрения формальной начиная с этого момента мы имеем неопределённое поведение, так как адресная арифметика дозволяется только над указателями, указывающими на элемент массива; &a не указывает на элемент массива.
Адресная арифметика дозволяется над указателями на массив из одного элемента Другое дело, что мы получаем валидный неразыменовываемый указатель "за конец массива", и вот попытка разыменовать его и является UB.
Здравствуйте, Кодт, Вы писали:
E>>Там вроде как разименование невалидного указателя. Это UB дальше может быть что угодно...
К>Валидного. Указатель за конец массива, а также нулевой указатель — вполне себе валидные
Ну, в смысле, негодного для разыменования...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском