Коллеги, помогите разложить по полочкам термин «указатель». У меня получается вот такое многообразие, правильность которого хотелось бы обсудить.
1.
Указатель – это адрес.
2.
Указатель-переменная – это переменная, которая содержит адрес «объекта». Как и у любой переменной у нее есть тип. Под «объектом» понимается переменная соответствующего типа или область памяти в «куче».
Указатель-выражение – это выражение, результатом вычисления которого является адрес.
int a = 1;
int *p = &a;
// p – указатель-переменная типа int.
// &a – указатель-выражение
3.
Часто в книгах/статьях/etc все это просто называют термином «указатель», не добавляя «переменную» или «выражение».
4.
У указателя-переменной тип задается при описании. А каким образом он «выводится» у указателя-выражения?
Здравствуйте, DirtyGarry, Вы писали:
DG>Коллеги, помогите разложить по полочкам термин «указатель». У меня получается вот такое многообразие, правильность которого хотелось бы обсудить. DG>4... DG>У указателя-переменной тип задается при описании. А каким образом он «выводится» у указателя-выражения? DG>Спасибо
Правила определения типа выражения в зависимости от его состава расписаны практически в любой книге по Си. Нет разницы, какое у вас выражение: математическое или с адресной арифметикой.
Попробую объяснить "на пальцах":
Для того, чтобы получить "указатель-выражение" нужно иметь какой-либо исходный адрес. Т.е. в выражении должен присутствовать хотя-бы один указатель. Например:
int a[10];
int *p = &a[0];
(p + 8) - 3 * 2; // "Укказатель-выражение" возвращает тип (int *), точно такой же, как и тип переменной p;
Пример посложнее:
( (short *)0xb80000000 ) + 10; // тип short *char *pchar = (char *)( (short *)0xb80000000 + 10 );
char ch = *pchar; // 10-й символ на экране в текстовом режиме
Нельзя складывать два указателя:
int a[2];
int *p1 = &a[0], *p2 = &a[1];
int *p = p1 + p2; // ошибка
//////////////////////////////////int a;
double b;
int *p1 = &a
double *p2 = &b;
int *p = p1 + p2; // тоже ошибка
--------------------
К указателям применимы операции сравнения и увеличения / уменьшения на число.
--------------------
Здравствуйте, DirtyGarry, Вы писали:
DG>Коллеги, помогите разложить по полочкам термин «указатель». У меня получается вот такое многообразие, правильность которого хотелось бы обсудить.
DG>1. DG>Указатель – это адрес.
Нет. Адрес — это число, а указатель — это нечто, содержащие адрес.
DG>2. DG>Указатель-переменная – это переменная, которая содержит адрес «объекта». Как и у любой переменной у нее есть тип. Под «объектом» понимается переменная соответствующего типа или область памяти в «куче».
Да.
DG>Указатель-выражение – это выражение, результатом вычисления которого является адрес.
Можно и так сказать.
DG>int a = 1; DG>int *p = &a;
DG>// p – указатель-переменная типа int.
нет. p – указатель-переменная типа int*
DG>// &a – указатель-выражение
Обычно говорят, что выражение &a — это выражения взятия адреса, результатом которого является указатель на a.
А, вот, например, (p+1) — указатель-выражение.
DG>3. DG>Часто в книгах/статьях/etc все это просто называют термином «указатель», не добавляя «переменную» или «выражение».
Бывает.
DG>4. DG>У указателя-переменной тип задается при описании. А каким образом он «выводится» у указателя-выражения?
Думаю, надо различать две вещи: операция взятие адреса и конвертация типа указателя в другой тип.
Здравствуйте, SaZ, Вы писали:
SaZ>Нельзя складывать два указателя:
SaZ>-------------------- SaZ>К указателям применимы операции сравнения и увеличения / уменьшения на число. SaZ>--------------------
Также определена разность указателей (тип ptrdiff_t).
BFE>Нет. Адрес — это число, а указатель — это нечто, содержащие адрес.
Адрес не обязан быть числом. Память может быть сегментной...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>Адрес не обязан быть числом. Память может быть сегментной...
Пусть пара чисел, ничего же не меняется, за исключением некоторых ограничений адресной арифметики.
Здравствуйте, DirtyGarry, Вы писали:
DG>Коллеги, помогите разложить по полочкам термин «указатель». У меня получается вот такое многообразие, правильность которого хотелось бы обсудить.
DG>1. DG>Указатель – это адрес.
ага щас блин. вот и выросло поколение которое не знает что такое near и far указатели и для вас сейчас все указатели это near. это не адрес. это индекс.
DG>2. DG>Указатель-переменная – это переменная, которая содержит адрес "объекта"
нет там никакого адреса.
> Как и у любой переменной у нее есть тип.
какой тип у *void? это ж прямое указание на то, что типа нет
DG>Указатель-выражение – это выражение, результатом вычисления которого является адрес.
это по ходу дела уже ваша терминология
DG>int *p = &a; DG>// p – указатель-переменная типа int.
указатель на тип int.
DG>// &a – указатель-выражение
грубо говоря тут имеет место быть взятие адреса, но на самом деле это не взятие адреса, а получение "магического пирожка". в общем случае это не адрес.
DG>У указателя-переменной тип задается при описании. А каким образом он «выводится» у указателя-выражения?
если a это int, то указатель на a очевидно int*. если a это int, b это char, то &(a+b) -- ошибка компиляции очевидно.
americans fought a war for a freedom. another one to end slavery. so, what do some of them choose to do with their freedom? become slaves.
Здравствуйте, pagid, Вы писали:
P>Пусть пара чисел, ничего же не меняется, за исключением некоторых ограничений адресной арифметики.
ID сегмента свойствами числа обладать не обязан...
В общем случае С-шный адрес более сложная структура, чем число... Стоит об этом помнить...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
P>>Пусть пара чисел, ничего же не меняется, за исключением некоторых ограничений адресной арифметики. E>ID сегмента свойствами числа обладать не обязан... E>В общем случае С-шный адрес более сложная структура, чем число... Стоит об этом помнить...
В компьютере — всё числа. Всегда можно raw-дамп получить.
Здравствуйте, McQwerty, Вы писали:
MQ>В компьютере — всё числа. Всегда можно raw-дамп получить.
Даже это не правда. Например ID сегмента может проверяться аппаратурой на валидность, просто при загрузке в соответствующий регистр. И сразу числа превратятся в слова Ну вроде 'APPL' и 'LINX'
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
MQ>>В компьютере — всё числа. Всегда можно raw-дамп получить. E>Даже это не правда. Например ID сегмента может проверяться аппаратурой на валидность, просто при загрузке в соответствующий регистр. И сразу числа превратятся в слова Ну вроде 'APPL' и 'LINX'
Уже, наверное, оффтопично, но! Числа _можно_ рассматривать как текст, числами они быть не перестают.
const unsigned i = 'APPL' + 'LINX'; // Вполе валидно.
А вот способа валлидно "складывать" или "вычитать" ID сегментов в С'шной модели памяти нет.
И даже если хакнешь и сложишьь как-то, получишь UB в результате, с вполне реалистичным аппаратным авостом на некоторых архитектурах...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
E>В общем случае С-шный адрес более сложная структура, чем число... Стоит об этом помнить...
В общем случае С-шный адрес это то, что указывает на некоторый участок памяти и с чем возможна адресная арифметика.
Здравствуйте, мыщъх, Вы писали:
DG>>1. DG>>Указатель – это адрес. М>ага щас блин. вот и выросло поколение которое не знает что такое near и far указатели и для вас сейчас все указатели это near. это не адрес. это индекс.
Указатель – это переменная, содержащая адрес другой переменной.
Керниган, Ритчи "Язык программирования C", стр. 105. Авторы тоже не знали про near и far ?
DG>>Указатель-выражение – это выражение, результатом вычисления которого является адрес. М>это по ходу дела уже ваша терминология
Выражение "pointer expression" встречается в стандарте C99. Возможно это мой корявый перевод...
Почему нельзя думать про указатель как про адрес? Те моменты, на которые Вы обращаете внимание, по-моему, имеют отношение к реализации компилятора. Или я не прав?
Здравствуйте, DirtyGarry, Вы писали:
DG>Почему нельзя думать про указатель как про адрес?
Мне нравится определение: указатель-абстрактная сущность, обеспечивающая адресацию объекта в системе ЯП
и реализуемая согласно особенностям конкретной аппаратной платформы.
Здравствуйте, Erop, Вы писали:
E>А вот способа валлидно "складывать" или "вычитать" ID сегментов в С'шной модели памяти нет.
Так и сегментов в С'шной модели памяти нет. Есть реализации более-менее удовлетворительно отображающие одно на другое.
Здравствуйте, smeeld, Вы писали:
S>Здравствуйте, DirtyGarry, Вы писали:
DG>>Почему нельзя думать про указатель как про адрес?
S>Мне нравится определение: указатель-абстрактная сущность, обеспечивающая адресацию объекта в системе ЯП S>и реализуемая согласно особенностям конкретной аппаратной платформы.
Ключевое слово выделено. Адрес -- это и есть что-то, что позволяет идентифицировать объект.
Например, адрес на конверте. Как он устроен при этом -- это детали реализации.
Поэтому указатель -- это именно адрес переменной.
для формального определения можете "припасть к первоисточнику", положим ISO/IEC 9899
в пункте 6.2.5 определяется pointer type как вид derived type (производный тип? как лучше не знаю)
в 6.3.2.3 поясняются возможные преобразования указателей
в 6.7.5.1 поясняются описатели указателей pointer declarators который и используется для конструирования производных типов
в 6.5.3.2 поясняется операция разыменования *