Здравствуйте, SaZ, Вы писали:
SaZ>Нельзя складывать два указателя:
SaZ>-------------------- SaZ>К указателям применимы операции сравнения и увеличения / уменьшения на число. SaZ>--------------------
Также определена разность указателей (тип ptrdiff_t).
Здравствуйте, DirtyGarry, Вы писали:
DG>Почему нельзя думать про указатель как про адрес?
Мне нравится определение: указатель-абстрактная сущность, обеспечивающая адресацию объекта в системе ЯП
и реализуемая согласно особенностям конкретной аппаратной платформы.
Здравствуйте, 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>У указателя-переменной тип задается при описании. А каким образом он «выводится» у указателя-выражения?
Думаю, надо различать две вещи: операция взятие адреса и конвертация типа указателя в другой тип.
Здравствуйте, pagid, Вы писали:
P>Пусть пара чисел, ничего же не меняется, за исключением некоторых ограничений адресной арифметики.
ID сегмента свойствами числа обладать не обязан...
В общем случае С-шный адрес более сложная структура, чем число... Стоит об этом помнить...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, Erop, Вы писали:
MQ>>В компьютере — всё числа. Всегда можно raw-дамп получить. E>Даже это не правда. Например ID сегмента может проверяться аппаратурой на валидность, просто при загрузке в соответствующий регистр. И сразу числа превратятся в слова Ну вроде 'APPL' и 'LINX'
Уже, наверное, оффтопично, но! Числа _можно_ рассматривать как текст, числами они быть не перестают.
const unsigned i = 'APPL' + 'LINX'; // Вполе валидно.
Здравствуйте, Erop, Вы писали:
E>В общем случае С-шный адрес более сложная структура, чем число... Стоит об этом помнить...
В общем случае С-шный адрес это то, что указывает на некоторый участок памяти и с чем возможна адресная арифметика.
Коллеги, помогите разложить по полочкам термин «указатель». У меня получается вот такое многообразие, правильность которого хотелось бы обсудить.
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; // тоже ошибка
--------------------
К указателям применимы операции сравнения и увеличения / уменьшения на число.
--------------------
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.
Здравствуйте, Erop, Вы писали:
P>>Пусть пара чисел, ничего же не меняется, за исключением некоторых ограничений адресной арифметики. E>ID сегмента свойствами числа обладать не обязан... E>В общем случае С-шный адрес более сложная структура, чем число... Стоит об этом помнить...
В компьютере — всё числа. Всегда можно raw-дамп получить.
Здравствуйте, McQwerty, Вы писали:
MQ>В компьютере — всё числа. Всегда можно raw-дамп получить.
Даже это не правда. Например ID сегмента может проверяться аппаратурой на валидность, просто при загрузке в соответствующий регистр. И сразу числа превратятся в слова Ну вроде 'APPL' и 'LINX'
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
А вот способа валлидно "складывать" или "вычитать" ID сегментов в С'шной модели памяти нет.
И даже если хакнешь и сложишьь как-то, получишь UB в результате, с вполне реалистичным аппаратным авостом на некоторых архитектурах...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Здравствуйте, мыщъх, Вы писали:
DG>>1. DG>>Указатель – это адрес. М>ага щас блин. вот и выросло поколение которое не знает что такое near и far указатели и для вас сейчас все указатели это near. это не адрес. это индекс.
Указатель – это переменная, содержащая адрес другой переменной.
Керниган, Ритчи "Язык программирования C", стр. 105. Авторы тоже не знали про near и far ?
DG>>Указатель-выражение – это выражение, результатом вычисления которого является адрес. М>это по ходу дела уже ваша терминология
Выражение "pointer expression" встречается в стандарте C99. Возможно это мой корявый перевод...
Почему нельзя думать про указатель как про адрес? Те моменты, на которые Вы обращаете внимание, по-моему, имеют отношение к реализации компилятора. Или я не прав?
Здравствуйте, 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 поясняется операция разыменования *
Здравствуйте, DirtyGarry, Вы писали:
DG>Здравствуйте, мыщъх, Вы писали:
DG>Указатель – это переменная, содержащая адрес другой переменной. DG>Керниган, Ритчи "Язык программирования C", стр. 105. Авторы тоже не знали про near и far
ветхий завет да еще на русском языке? читайте в первоисточнике. near и far главным образом относятся к интел. адрес это сегмент (селектор) и смещение (оно же индекс). указатели в плоской модели памяти суть индексы. исключение составляет fs, который винда заюзала для своих целей. у него другой базовый адрес и лимиты нежели cs (код), ss (стек) и ds (данные).
на микроконтроллерах -- там и сегодня цырк с 8-, 16- и 24-битными указателями.
flash char string[] = "This string is stored in flash";
char flash *flashpointer; ; Declare flash pointer
flashpointer = &string[0]; ; Assign pointer to flash location
обратите на тип указателя -- flash. если бы указатели содержали адрес переменных, то зачем бы потребовалось дополнительно указывать, что это флеш? ведь и так ясно ж. но хочется экономить биты и юзать не адреса, а индексы.
DG>Выражение "pointer expression" встречается в стандарте C99. Возможно это мой корявый перевод...
гм, ну выражение-то встречается и даже раньше C99, но ему не придают специального смысла. это скорее к разбору a = ***b; ну и чтобы понять почему a[b] тождественно b[a] (например p[0] можно заменить на 0[p]) нужно свести это к выражению. потому что там тупо сумма берется. а от перестановки слагаемых...
DG>Почему нельзя думать про указатель как про адрес?
потому что это даже у рихтера описано. в реальной жизни на реальных осях есть проблема: есть переменная, содержащая адрес другой переменной. пускай для определенности это список. казалось бы что может быть проще пройтись по этому списку. как только вы решите эту проблему -- сразу снанете очень богатым человеком.
> Те моменты, на которые Вы обращаете внимание, по-моему, имеют отношение к реализации компилятора. Или я не прав?
их приходится учитывать когда вы работате с указателями разных типов. это выходит за рамки стандарта. но это реальность. и с ней приходится считаться.
если вы хотите понять что там происходит с указателями -- нужно хотя бы смотреть какие типы указателей поддерживает компилятор и позволяет ли "скрещивать" указатели разных типов в одном выражении. обычно не позволяет. потому что если foo и bar это 16 битные указатели (а по сути индексы 16 битных блоков памяти), то в них нет информации, позволяющей понять что там за блоки.
пускай foo указаывает на блок А, а bar на блок Б. выражение (*foo == *bar) лишено смысла. компилятор скорее всего использует какой-то один блок, а не два. это, разумеется, в случае коротких указателей. можно использовать длинные и проблемы не будет (в них будет базовый адрес блока в виде секлектора скорее всего), но это жуткой тормоз...
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.
Здравствуйте, мыщъх, Вы писали:
DG>>Керниган, Ритчи "Язык программирования C", стр. 105. Авторы тоже не знали про near и far М>ветхий завет да еще на русском языке? читайте в первоисточнике.
Что-то мне подсказывает, что в первоисточнике написано так же.
DG>>Почему нельзя думать про указатель как про адрес? М>потому что это даже у рихтера описано.
Можете сказать, где именно посмотреть и что искать?
>> Те моменты, на которые Вы обращаете внимание, по-моему, имеют отношение к реализации компилятора. Или я не прав? М>их приходится учитывать когда вы работате с указателями разных типов. это выходит за рамки стандарта. но это реальность. и с ней приходится считаться.
Правильно ли я понимаю, что Вы говорите про strict aliasing rules, restrict и т.п.? Если да, то получается, что если вы не разработчик компилятора или вам не нужно написать какой-то хитро эффективный код, вы вполне можете обойтись представлением об указателе как об адресе в некотором «абстрактном адресном пространстве». Кроме того, код, который нарушает strict aliasing rules, по-моему, должен приводить к неопределенному поведению.
Написал, а потом задумался . Я главным образом пишу про разработку прикладных приложений, а что там в ядре – большой вопрос. Но, по-моему, все равно должен быть какой-то уровень абстракции, только после которого появятся селекторы, сегменты и т.п.
Да не мыщъх, посоны тебе правильно толкуют. Это детали реализации. Адрес не обязательно число, адрес может может быть чем угодно. Главное, чтобы были реализованы операции (address) +/- (offset) = (address), (address) — (address) = (offset), *(address) = (something). Остальные операции зависят от реализации.
Здравствуйте, мыщъх, Вы писали:
М>ветхий завет да еще на русском языке? читайте в первоисточнике. near и far главным образом относятся к интел. адрес это сегмент (селектор) и смещение (оно же индекс). указатели в плоской модели памяти суть индексы. исключение составляет fs, который винда заюзала для своих целей. у него другой базовый адрес и лимиты нежели cs (код), ss (стек) и ds (данные).