Присвоение адреса целочисленной переменной

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

int a=0x28ff1c

Вы можете сделать то же самое для переменной char, компилятор не выдаст ошибку

char b=0x28ff1c

Он выведет на экран консоли мусорное значение для char b и случайное значение для int a

cout<<b
    <<endl;
cout<<a;

Может кто-нибудь объяснить мне, почему есть разница в выводе для char b и int a. Может ли кто-нибудь объяснить мне, почему переменной char и целочисленной переменной могут быть назначены адреса?


person Computernerd    schedule 30.12.2012    source источник
comment
0x28ff1c является целым числом.   -  person Mat    schedule 30.12.2012


Ответы (4)


Число 0x28ff1c — это просто шестнадцатеричное (по основанию 16) представление десятичного (по основанию 10) числа 2686748. Поскольку cout по умолчанию печатает десятичные значения для целых чисел, это, вероятно, число, которое вы напечатали.

Случай с char b = 0x28ff1c немного отличается, т.к.

  1. char недостаточно велик для хранения этого значения. Практический результат заключается в том, что он усекается до 0x1c.
  2. cout обрабатывает char особым образом, потому что он обычно используется для хранения текстовых данных, поэтому cout печатает символ с кодом 0x1c, который является своего рода управляющим символом. Вы можете попробовать это, например, с 0x41 (что представляет 'A' в ASCII и UTF-8).

И обратите внимание, что нет ничего, что помечало бы 0x28ff1c как адрес. Адрес будет сформирован &a или (void*)0x28ff1c.

person Bart van Ingen Schenau    schedule 30.12.2012
comment
(char*)0x28ff1c безопаснее (если вы не можете гарантировать, что 0x28ff1c правильно выровнено для int) - cc. @Lim Бонусный вопрос - усечен ли результат или это неопределенное поведение из-за переполнения (учитывайте, что char подписано)? - person Luchian Grigore; 30.12.2012
comment
@LuchianGrigore Определяется реализацией (кроме CHAR_BIT >= 23), он может насыщать, усекать, отображать все значения вне диапазона до 13, реализация просто должна документировать то, что она делает. В C он может даже вызвать сигнал, определяемый реализацией. - person Daniel Fischer; 30.12.2012

0x28ff1c не является адресом, это просто шестнадцатеричное число.

Следующие эквивалентны:

int a =   2686748;  //decimal number
int a =  0x28ff1c;  //hexadecimal number
int a = 012177434;  //octal number

Адрес представлен указателем — если это просто адрес, вы можете использовать void*:

void* p = (void*)0x28ff1c;

В таком случае

int a = p;

не будет компилироваться. p — это адрес, а не сам номер.

person Luchian Grigore    schedule 30.12.2012
comment
@Luchin, как вы объясните разницу в выводе int a и char b и почему компилятор не выдает ошибку при присвоении целочисленного значения char b - person Computernerd; 30.12.2012
comment
@Lim char имеет размер всего 1 байт, поэтому он не может содержать все значение. Предупреждение может быть выдано, но не обязательно. Вы в основном переполняете переменную char (поэтому она печатает неверный результат). - person Luchian Grigore; 30.12.2012

Потому что в любом литеральном начале 0x на самом деле является целым числом. Так что это разрешено. Адрес is иногда может быть целым числом.

person Vincent Ramdhanie    schedule 30.12.2012
comment
Адреса не являются целыми числами. Во многих реализациях можно без проблем преобразовывать адреса в целые числа. В некоторых реализациях адреса могут иметь структуру, которая плохо представлена ​​в виде одного целого числа (например, добавление 1 к кодировке адреса может не привести к получению адреса, который находится на 1 байт дальше в памяти). - person Eric Postpischil; 30.12.2012
comment
Хороший вопрос @EricPostpischil. Я скажу Иногда адрес может быть целым числом - person Vincent Ramdhanie; 30.12.2012
comment
@EricPostpischil Я не понимаю, насколько это актуально. Конечно, не гарантируется, что int содержит адрес, но арифметика указателей здесь не рассматривается. То, что вы указали (добавление к адресу), гораздо сложнее (может привести даже к УБ). - person Luchian Grigore; 30.12.2012
comment
@LuchianGrigore: Это актуально, потому что было сделано утверждение, которое является ложным и способствует неправильной ментальной модели у людей, изучающих программирование. - person Eric Postpischil; 30.12.2012
comment
@EricPostpischil определенно, адрес не является целым числом. Ну да, но не int. Я не спорил с этим. Просто есть много придирок, которые не могут быть полностью описаны в комментарии. - person Luchian Grigore; 30.12.2012
comment
@LuchianGrigore: Что касается «Ну, это так, но не int». Нет, это неправильно. Во многих системах с плоским адресным пространством адреса могут быть по существу эквивалентны целым числам. Но есть системы, на которых их нет. Одним из простейших контрпримеров является адресация с базовым смещением, где адрес представляет собой не одно целое число, а два целых числа. Тогда адресная арифметика и целочисленная арифметика сильно различаются: добавление единицы к адресу может зациклиться на сегменте. Вычитание адресов в разных сегментах обычно не дает количества байтов между ними. - person Eric Postpischil; 30.12.2012
comment
@EricPostpischil Это новое для меня. Не могли бы вы дать мне еще несколько ресурсов по этому поводу? (Я хотел бы знать больше) - person Luchian Grigore; 30.12.2012
comment
@LuchianGrigore: Извините, у меня нет под рукой ссылки; Я не узнал об этом из современных ссылок; Я пережил это. Вероятно, самый простой способ увидеть это сегодня на потребительских машинах — это попробовать программирование для MS-DOS или ранних версий Windows. Возможно, MSVC все еще поддерживает сборку для старых моделей адресов. По сути, адрес будет представлять собой базу и смещение, а физический адрес будет примерно таким: 64*база+смещение. Таким образом, основание 0 и смещение 64 будут тем же адресом, что и основание 1 и смещение 0. Но были и более сложные адресные пространства… - person Eric Postpischil; 30.12.2012
comment
Адрес может быть номером сегмента и смещением, а номер сегмента может быть индексом в таблице, где будет храниться базовый адрес. Тогда нет фиксированной арифметики от номера сегмента и смещения до полного адреса. Вам также понадобится запись в таблице, чтобы сформировать полный адрес. «Указатели» в C должны были бы состоять из составной информации. MSVC имел (имеет?) разные типы указателей для разных ситуаций (длинные указатели, ближние указатели и т. д.). - person Eric Postpischil; 30.12.2012
comment
Еще два комментария, чтобы добавить разные аспекты. Возможно, нам следует создать для них новый вопрос. Во-первых, некоторые системы, с которыми я не знаком напрямую, имеют разные типы указателей для разных объектов. Представьте себе машину с 48-битными словами, доступ к которым можно получить только по номеру слова. Чтобы обрабатывать строки байтов, компилятор должен изобретать адреса для байтов внутри слов и генерировать код для извлечения или объединения байтов. Если вы используете три бита для кодирования того, какой 8-битный байт в 48-битном слове требуется, то вы используете только значения 0-5. 6 и 7 не используются. Тогда адресная арифметика становится странной. - person Eric Postpischil; 30.12.2012
comment
Таким образом, адресные пространства, подобные этим, являются причиной того, что C и C++ имеют правила арифметики указателей. Правила выполнения адресной арифметики только внутри массива? Это сделано для того, чтобы компилятору не нужно было гарантировать, что разные объекты используют одну и ту же базу для своего базового адреса + смещение. Вы можете выполнять арифметические действия внутри массива, потому что массив имеет только одно основание. Как только вы выйдете за пределы массива, простая арифметика по адресу base+offset может не сработать. Правила преобразования типов указателей? Это позволяет избежать проблем с преобразованием адресов байтов в словах в адреса слов и так далее. - person Eric Postpischil; 30.12.2012
comment
Я разместил этот вопрос для сбора информации об адресных пространствах. - person Eric Postpischil; 30.12.2012

Вы также можете использовать *(int *)(Address) = value в качестве конструкции для назначения value Address и использовать ответ @Luchian Grigore

person Shan    schedule 30.12.2012