Интересно, что на самом деле возвращает & a? - PullRequest
7 голосов
/ 09 сентября 2011

Предположим,

Первый случай

 int a;
 int *p= &a ; it works no error

Второй случай

 long int a;
 long int b;
 b = & a; it wont work 

Большинство из нас говорят, что b - это переменная, а не указатель. Но смотрите ниже.

Таким образом, вопрос в том, если &a возвращает адрес, который является целым числом без знака, то почему мы не можем присвоить его нормальной переменной? Но почему только указатели? Смотри ниже

b = (unsigned int) &a ; it works after typecasting though its not practicable.

Если адрес имеет целочисленный формат, то почему его не сохраняют целые числа без знака или длинные? Я думал, что за этим должен быть какой-то скрытый секрет. Кто-нибудь может это раскрыть? Я думал, что указатели должны что-то делать внутри, но мне интересно, что это будет и почему нормальная переменная не может быть.

Спасибо за все ваши ответы, кроме реального вопроса, что на самом деле возвращает &a? Целочисленное значение или нет? если это целое число, почему переменная не может его содержать? long int a = 65535 \ valid, почему не int a = & b, если значение адреса b равно 65535

Я не беспокоюсь о том, чтобы использовать его в качестве указателя, пожалуйста, вопрос только о сохранении значения. Не ссылаясь на адрес. Люди, говорящие 32 или 64 бит, я не беспокоюсь об этом. Почему нельзя сохранить адрес, если адрес представляет собой целое число?

Я имею в виду, почему мы не можем присвоить значение, я не говорю, чтобы назначить свойства указателей на переменную, а просто назначить значение, которое это

a=65535
b = a \\ works it assigns b - 65535
&a=65535
b = & a   \\ doesn't work, if address is a some integer value,why we can't store it in a variable?

Возьмем 16 бит в качестве примера. Размер нормального указателя (адреса) составляет 2 байта, а размер переменной - 2 байта. Почему мы не можем сохранить адрес в другой переменной, если адрес - целочисленное значение? увеличивает значение на 4 для указателя и значение 1 для переменной, не беспокойтесь о том, что просто присвоение значения является более важным вопросом.

  b = & a ; address of a is 4000
  ++b ; becomes 4001 thats it,thats not a problem 

Ответы [ 9 ]

22 голосов
/ 09 сентября 2011

Целые числа, даже long int, не всегда будут иметь тот же размер, что и указатель.Иногда они будут (например, большинство 32-разрядных архитектур имеют sizeof(int) == sizeof(void *)), иногда они будут другими (например, некоторые 64-разрядные архитектуры имеют sizeof(long) == sizeof(void *), а некоторые нет - Visual C ++ в Windows является простымпример компилятора, где sizeof(long) != sizeof(void *)).

Существует также тот факт, что void * просто не совпадает с type с long int.

Представьте себе классFoo и класс Bar, определенные следующим образом:

class Foo {
   public: int a;
};

class Bar {
   public: int b;
};

Это все равно, что спросить, почему вы не можете назначить экземпляр класса Foo переменной типа Bar - ониэто не одно и то же, хотя в этом случае и Foo, и Bar имеют одну и ту же базовую битовую комбинацию.

7 голосов
/ 09 сентября 2011

возвращает адрес, который является целым без знака

Нет, это не так. Указатель (адрес) является указателем. Период.

6 голосов
/ 09 сентября 2011

Вы можете, и это было очень распространено, сейчас это актуальная проблема переносимости, поскольку ее нельзя использовать на платформах x64 с 64-разрядным указателем и 32-разрядным целым числом.

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

Это не слишком разумно в современном использовании, поскольку это может легко привести к ошибкам и путанице. Улучшения безопасности типов в дизайне компилятора запрещают такое использование, но C99 повторно вводит некоторую аналогичную поддержку с uintptr_t и intptr_t, которые являются «целочисленными типами, способными содержать указатели объектов».

Перефразируя ваш вопрос:

Почему мы не можем присвоить [указатель] на [целочисленную] переменную?

Ответ таков: поскольку это не ассемблер, C и C ++ являются строго типизированными языками.

3 голосов
/ 09 сентября 2011

Это не специфично для C или C ++. Это одинаково для всех строго типизированных языков. Это в некоторой степени даже верно в английском языке. Можно сказать, что «цвет книги синий», но не «цвет книги деревянный». A type ограничивает возможные значения , которые может иметь переменная.

Тип переменной int* может содержать только значения, которые являются адресами типа int, а переменная типа long int может содержать значения только от LONG_MIN до LONG_MAX включительно. Это просто два совершенно разных набора значений.

C и C ++ не являются абсолютными. Typecasting позволит вам обойти некоторые ограничения. Например. (int) 3.5 сообщает компилятору, что вы хотите преобразовать нецелое значение 3.5 в приблизительно аналогичное целочисленное значение. Это работает лучше, если два типа более похожи. Другие языки могут не иметь такой типизации; там вам может потребоваться вызвать функцию вместо этого. Например. ROUND(3.5, INT)

2 голосов
/ 09 сентября 2011

если адрес имеет целочисленный формат, то почему его не сохраняют беззнаковые или длинные целые числа?Я думал, что за этим должен быть какой-то скрытый секрет.

Адрес не является целым числом;это адрес.В 64-битной системе это:

int *p; 

выделяет 64-битную переменную, тогда как это:

int b; 

выделяет 32-битную переменную.Они не одинаковы.Они могут показаться одинакового размера в некоторых системах, но они не одинаковы.Рассмотрим в качестве одного примера оператор ++.В 32-разрядной системе ++ для указателя увеличивает указатель на 4, тогда как ++ для целого числа увеличивает целое число на 1. Компилятор пытается помочь вам, сообщая вам, что вы делаете что-то не так.

2 голосов
/ 09 сентября 2011

Нико, ИМХО смысл типизированных языков состоит в том, что вы не можете просто назначить одну вещь другой, даже если они всего лишь куча битов на самом низком уровне.

1 голос
/ 09 сентября 2011

Из того, что я получаю из вашего вопроса, у вас сложилось впечатление, что, поскольку адрес представлен в шестнадцатеричном виде, это целое число. Ну, конечно, но это не значит, что вы можете поместить целое число в указатель так, как вы думаете.

Данные (переменная) имеют информацию вместе с метаданными. Размер, значение, тип данных .... адрес, где он хранится. Указатель содержит последний кусок метаданных, адрес. Это особый тип данных, основной задачей которого является хранение адресов. Значение указателя не зависит от значения данных, это две разные вещи. Значение указателя говорит вам, где найти данные, которые вы ищете. Вот почему вы не можете поместить целое число в указатель так, как вы пытаетесь. Это все равно что сказать, что вы живете по какому-то уличному адресу, и вы тоже этот адрес. Представь, если бы люди звали тебя по твоему адресу, это было бы глупо!

Учтите это: у вас есть класс с именем x, который содержит несколько членов. Вы создаете указатель на этот класс. Указатель по-прежнему содержит адрес в шестнадцатеричном формате. Но объект не может быть разбит на 4 или 8 байт (32-битное и 64-битное соответственно) значение! Обратите внимание, что формат указателя для всех типов данных одинаков, независимо от их значения.

 int a;  int *p= &a;

Теперь ... причина, по которой это сработало, заключается в том, что вы взяли адрес переменной a и поместили его в указатель p. Ключевое слово - АДРЕС, это то, что содержит указатель.

 long int a;   
 long int b;   
 b = & a; 

Это не сработало, потому что вы попытались поместить АДРЕС (указатель) a в b, который является просто переменной.

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

1 голос
/ 09 сентября 2011

Указатели обычно реализуются как целые числа, но спецификация C ++ определяет только их поведение (где должны быть одинаковые или разные два указателя и т.некоторый другой класс / тип.

Относительно того, почему b = (uint) &a; работает, возможно, это зависит от реализации.(И арко-зависимый).

0 голосов
/ 12 сентября 2011

В вашем первоначальном мышлении есть неправильное представление: есть "нормальные переменные" и "позитнеры". Там нет такого понятия. Есть только «переменные» и «типы».

  • int - это «контейнер для целочисленного значения»
  • class Person - это контейнер для описания Person.
  • int * является контейнером для адреса целого числа
  • Person * - это контейнер для адреса Person.

Оператор & возвращает адрес переменной, а ее тип является «указателем на этот тип». Присваивания могут идти только от выражения данного типа к переменной совместимого типа. int, int *, Person и Person * несовместимы друг с другом. Вы не можете назначить int * для int по той же причине, по которой вы не можете назначить Person для int или int для Person. Если у вас нет функции, которая позволяет вам написать выражение, возвращающее один тип из другого. точно так же, как operator & делает и выражение &a дает вам.

...