Почему этот код печатает 0

0

Почему следующий код печатает 0? т.е. почему переменная a расположена сразу после переменной d, даже если между ними объявляется переменная c указателя?

#include<iostream>
using namespace std;

int main () {
    unsigned int a = 100;
    unsigned int &b = a;
    unsigned int *c = &b;
    unsigned int d = (unsigned int)(c);
    int e = &d - c;
    int &f = e;
    e ++;
    cout << e << " " << endl;
    return 0;
}
Теги:
pointers
variables
memory

3 ответа

2
Лучший ответ

Работа в обратном направлении:

e ++;
cout << e << " " << endl;

Если это печатает 0, то значение e перед выполнением этого кода должно быть -1.

int e = &d - c;

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

unsigned int a /* = whatever, the value of a doesn't matter */;
unsigned int &b = a;
unsigned int *c = &b;
unsigned int d /* = whatever, the value of d doesn't matter */;

b является ссылкой на a, поэтому &b эквивалентно &a.

Итак, &d - c эквивалентно &d - &a, и это вычитание дает -1.

Вывод: адрес d является sizeof (unsigned int) после адреса a. (Вычитание указателя масштабируется по размеру указанного типа.)

Вероятно.

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

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

Вероятно, с учетом выхода вашей программы, чтобы b и d были распределены рядом друг с другом. Ничто не говорит о том, что объявленные переменные должны быть распределены в том порядке, в котором вы их объявляете. Если вы хотите, чтобы объекты были выделены в памяти в порядке определения, поместите их в struct или сделайте их элементами массива.

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

И компилятору разрешено предположить, что поведение вашего кода хорошо определено и выполняет преобразования, которые являются действительными только с учетом этого предположения. Фактически, вычитая два несвязанных указателя, вы пообещали компилятору, что оба они указывают на элементы одного и того же объекта массива или только за ним (где один объект рассматривается как 1-элементный массив) (или что оба являются нулевыми указателями, это одно отличие между C и C++). Вы лгали компилятору, а это значит, что он не несет никаких дополнительных обязательств перед вами.

Не делай этого.

  • 1
    b самом деле b - это ссылка, привязанная к a , поэтому процесс «обратной работы» должен технически включать один дополнительный шаг: &b на самом деле &a , что означает, что &d - c эквивалентно &d - &a . Но ФП, видимо, это уже знает, поскольку это именно то, что указано в вопросе.
  • 0
    @AndreyT: Ах, я пропустил ссылку. Исправлена.
0

Если вы явно не размещаете объекты с помощью собственной системы управления памятью, их относительные позиции в памяти будут compiler- и зависят от системы.

-2

ваша строка int e = &d - c; вычитает 2 unsigned int *.

В памяти &d - 8 байт дальше, а затем c (это зависит от вашей системы, но мы полагаем, что int составляет 4 байта). Эффективно вы создаете свой стек таким образом:

unsigned int a = 100;                // &a is 0x0
unsigned int &b = a;                 // &b is 0x0 (it just an alias)
unsigned int *c = &b;                // &c is 0x4
unsigned int d = (unsigned int)(c);  // &d is 0x8

unsigned int использует 4 байта в памяти. Итак, когда вы делаете &d - c, он должен возвращать 2, потому что вы используете арифметику указателя с unsigned int* (4 * 2 = 8);

Вы можете попробовать с int e = (short*)&d - (short*)c результат должен быть 4 потому что short размер равен 2 (2 * 4 = 8).

Вы можете попробовать с int e = (char*)&d - (char*)c результат должен быть 8 потому что размер char равен 1 (1 * 8 = 8).

Попробуйте распечатать переменные и адреса, чтобы понять:

#include<iostream>
using namespace std;

int main () {
  unsigned int a = 100;
  unsigned int &b = a;
  unsigned int *c = &b;
  unsigned int d = (unsigned int)(c);
  int e = (short*)&d - (short*)c;
  //int &f = e;                                                                                                                                                                  
  //e ++;                                                                                                                                                                        

  cout << "&a: " << (unsigned int)&a << endl;
  cout << "&b: " << (unsigned int)&b << endl;
  cout << "&c: " << (unsigned int)&c << endl;
  cout << "&d: " << (unsigned int)&d << endl;

  cout << endl;

  cout << " a: " << a << endl;
  cout << " b: " << b << endl;
  cout << " c: " << (unsigned int)c << endl;
  cout << " d: " << d << endl;

  cout << endl;

  cout << " e: " << e << endl;
  return 0;
}

Здесь, с int e = (short*)&d - (short*)c; , результат:

&a: 3220197356
&b: 3220197356
&c: 3220197360
&d: 3220197364

 a: 100
 b: 100
 c: 3220197356
 d: 3220197356

 e: 4

Ещё вопросы

Сообщество Overcoder
Наверх
Меню