Здравствуйте, _cin_, Вы писали:
__>Здравствуй, All! __>Вопрос такой для чего указатель объявляется с типом: __>
__>int* x = 0;
__>
__>Ведь в
x
все равно хранится адрес, стало быть какого бы типа не был указатель, его размер в динамической памяти будет одним и тем же (имеется в виду размер самого указателя). В описании грамматики (Страуструп, приложение А) ничего не понял. В главе об объявлении переменных сказано, что * является одним из возможных операторов объявлений. Все равно ничего не понятно. Может кто нибудь оъяснить этот вопрос? Хочется знать что я пишу, а то пишешь, а почему так пишешь не в курсе.
Указатель объявляется с типом для того, чтобы например работала адресная арефметика. Когда ты вызываешь для указателя напимер operator ++(), то значение удреса хранящегося в указателя увеличивается на размер статического типа указателя (в данном примере это будет sizeof(int)). Еще возможно для того, чтобы избежать определенных логических ошибок, когда ты указателю на int например присваиваешь указатель на char.
Здравствуй, All!
Вопрос такой для чего указатель объявляется с типом:
int* x = 0;
Ведь в
x
все равно хранится адрес, стало быть какого бы типа не был указатель, его размер в динамической памяти будет одним и тем же (имеется в виду размер самого указателя). В описании грамматики (Страуструп, приложение А) ничего не понял. В главе об объявлении переменных сказано, что * является одним из возможных операторов объявлений. Все равно ничего не понятно. Может кто нибудь оъяснить этот вопрос? Хочется знать что я пишу, а то пишешь, а почему так пишешь не в курсе.
Здравствуйте, Анатолий Широков, Вы писали:
АШ>С++ строго типизированный язык, если бы указатель объявлялся без типа, то как бы понял компилятор на что он указывает:
Здравствуйте, Анатолий Широков, Вы писали:
АШ>С++ строго типизированный язык, если бы указатель объявлялся без типа, то как бы понял компилятор на что он указывает:
АШ>
АШ>int i;
АШ>[int]* p = &i; // int опущен
АШ>*p = 10; // а откуда компилятору знать на что указывает p?
АШ>
Но ведь компилятор уже знает какой тип у i. Что-то я запутался. У Страуструпа это описано?
АШ>>С++ строго типизированный язык, если бы указатель объявлялся без типа, то как бы понял компилятор на что он указывает:
АШ>>
АШ>>int i;
АШ>>[int]* p = &i; // int опущен
АШ>>*p = 10; // а откуда компилятору знать на что указывает p?
АШ>>
__>Но ведь компилятор уже знает какой тип у i. Что-то я запутался. У Страуструпа это описано?
Положим, у вас есть указатель на массив элементов.
int c[20];
..
void some_fun(int *p)
{
for (;*p; ++p)
...
}
some_fun(c);
Чтобы вычислить адрес следующего элемента (++p), компилятору надо знать размер элемента, то бишь его тип. Андерстенд? В С указатель это не только указатель, но и итератор.
Здравствуйте, _cin_, Вы писали:
__>Здравствуй, All! __>Вопрос такой для чего указатель объявляется с типом: __>
__>int* x = 0;
__>
__>Ведь в
x
все равно хранится адрес, стало быть какого бы типа не был указатель, его размер в динамической памяти будет одним и тем же (имеется в виду размер самого указателя).
Это неверно. Размер указателя зависит от типа указателя, потому что помимо адреса он может хранить различную служебную информацию, необходимую для правильной работы этих указателей.
Здравствуйте, _cin_, Вы писали:
__>Здравствуйте, Анатолий Широков, Вы писали:
АШ>>С++ строго типизированный язык, если бы указатель объявлялся без типа, то как бы понял компилятор на что он указывает:
АШ>>
АШ>>int i;
АШ>>[int]* p = &i; // int опущен
АШ>>*p = 10; // а откуда компилятору знать на что указывает p?
АШ>>
__>Но ведь компилятор уже знает какой тип у i. Что-то я запутался. У Страуструпа это описано?
Здесь — знает. Давай по-другому напишем.
void* p; // есть в С/С++ специальный обезличенный тип.int i;
double j;
if(rand()%2)
p = &i;
else
p = &j;
*p = 10; // ну и как компилятор узнает, на объект какого типа указывает p ?
Конечно, бывают компьютеры, у которых типизированная память. Т.е. по адресу (или содержимому) ячейки можно однозначно определить тип данных.
Но это экзотика.
Конечно, можно реализовать это свойство программно — большинство скриптовых языков, например.
Но один из принципов С++ — "не платить за то, что тебе не надо".
Повсеместная динамическая типизация означает, что у каждого данного сбоку есть тэг типа. Это расход и памяти, и времени.
Сделать "универсальный указатель" можно, даже без помощи шаблонов (но с шаблонами удобнее ). Но в большинстве случаев он не нужен (а то и вреден — из-за непредсказуемости, поскольку преобразования типов возлагаются на рантайм, и можно прощёлкать смысловые ошибки).
Hello, jazzer!
You wrote on Wed, 24 Aug 2005 22:09:18 GMT:
j> __>Здравствуй, All! j> __>Вопрос такой для чего указатель объявляется с типом: j> __>
j> __>int* x = 0;
j> __>
j> __>Ведь в
x
все равно хранится адрес, стало быть какого j> бы типа не был указатель, его размер в динамической памяти будет j> одним и тем же (имеется в виду размер самого указателя).
j> Это неверно. Размер указателя зависит от типа указателя, потому что j> помимо адреса он может хранить различную служебную информацию, j> необходимую для правильной работы этих указателей.
все равно хранится адрес, стало быть какого j>> бы типа не был указатель, его размер в динамической памяти будет j>> одним и тем же (имеется в виду размер самого указателя).
j>> Это неверно. Размер указателя зависит от типа указателя, потому что j>> помимо адреса он может хранить различную служебную информацию, j>> необходимую для правильной работы этих указателей.
__>А что это за информация, и где она хранится?
Могу предположить.
Если физическая адресация — не по байтам, а по чересчур большим словам, но при этом побайтовый доступ тоже есть (пример — IBM360°), то объявить "Сишный байт" размером в слово — это, во-первых, жлобство, а во-вторых, не соответствует логике (т.к. вывод строк — посимвольный, а каждый символ кодируется октетом).
° Я не в курсе ситуации с компиляторами С/С++ конкретно на IBM360 и ЕС. Может быть, там действительно 36-битный char.
Тогда указатель на байт — это пара (адрес, номер байта в слове), а указатели на все остальные типы (на выравненные данные) — это только адреса.
Естественно, чтобы обеспечить корректное восстановление char* -> void* -> char*, придётся void* тоже сделать составным.
И тут окажется, что char* -> void* -> anything_else* -> void* -> char*, будучи неопределённым поведением, даёт о себе знать.