все переменные хранятся непрерывно в зависимости от того, в каком порядке они объявлены в программе? - PullRequest
2 голосов
/ 30 октября 2019

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

Я поиграл с массивом char и переменной char.

   //this occurs within int main()

   char vowels[]{'a', 'e', 'i', 'o', 'u'};
   char x = 'x';

   std::cout << vowels[5]; //this outputs x

это заставило меня задуматься, все ли переменные хранятся в том порядке, в котором они объявлены.

Ответы [ 3 ]

1 голос
/ 30 октября 2019

Из стандарта ( 7.6.9.4 ):

Результат сравнения неравных указателей на объекты определяется в терминах частичного порядка в соответствии со следующими правилами:

  • Если два указателя указывают на разные элементы одного и того же массива или его подобъектов, указатель на элемент с более высоким нижним индексом требуется для сравнения большего.

  • Если два указателя указывают на разные нестатические элементы данных одного и того же объекта или субобъекты таких элементов, рекурсивно, указатель на объявленный позже элемент требуется для большего сравнения, если два члена имеют одинаковый доступcontrol ([class.access]), ни один из членов не является подобъектом нулевого размера, а их класс не является объединением.

  • В противном случае для сравнения больших значений ни один указатель не требуетсячем другое.

Поскольку первые два предложения не применяются для сравнения адреса x с адресомvowels или его элементы, их адрес по смыслу не сопоставим.

Но в этом сценарии именно указатель vowels + 5 (адрес, который vowels[5] пытается разыменовать) имеет особое значение. Любой указатель на гипотетический элемент с индексом n массива с n элементами известен как «один после указателя конца». Он представляет первый байт после конца массива. Разрешено вычислять этот адрес, но не разыменовывать его. В стандарте есть примечание, которое явно указывает на то, что вы вообще не можете использовать vowels[5] ( 6.8.2.3 ):

[...] Указатель за концомобъекта ([expr.add]), как полагают, не указывает на несвязанный объект типа объекта, который может быть расположен по этому адресу. [...]

Так что, даже если x точно на vowels + 5, вы все равно не можете получить к нему доступ через vowels[5].

0 голосов
/ 31 октября 2019

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

Нет, или, по крайней мере, язык не определяет его (см. Франсуа Андрие ответ ). Расположение переменных в памяти (в частности, переменных, не являющихся членами в стеке) зависит от усмотрения компилятора. Поскольку компилятор должен обрабатывать требования архитектуры, такие как выравнивание, он может переставлять переменные и оставлять пропуски между ними. Это может быть важно для оптимизации.

Вот пример (x86-64), где компилятор (clang-9) не размещает переменные в порядке объявления ...

#include <iostream>

int main() {

  char a[] {'a', 'b'};
  int x;

  std::cout << "&a[0] = " << (void*) &a[0] << std::endl;
  std::cout << "&a[1] = " << (void*) &a[1] << std::endl;
  std::cout << "&x = " << &x << std::endl;

  return 0;
}
&a[0] = 0x7ffd5becf02a
&a[1] = 0x7ffd5becf02b
&x = 0x7ffd5becf024
0 голосов
/ 30 октября 2019

это заставило меня задуматься, все ли переменные хранятся смежно в порядке, в котором они объявлены

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

...