Доступ к массиву C ++

скажем у меня есть:

int test[10];

на 32-битной машине. Что делать, если я делаю:

int b = test[-1];

Очевидно, что это большой отказ, когда дело доходит до доступа к массиву (вне границ), но что на самом деле происходит? Просто любопытно

Я получаю доступ к 32-битному слову «до» моего массива?

int b = *(test - 1);

или просто адрес очень далекого слова (начиная с «тестовой» ячейки памяти)?

int b = *(test + 0xFFFFFFFF);

0xFFFFFFFF — это двоичное представление в виде десятичного числа -1

0

Решение

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

Это может произойти так: если у вас 32-битный тип int, вы обращаетесь к 32-битной памяти в стеке (если есть) перед тестом [0] и приводите его к типу int. Ваш процесс может даже не владеть этой памятью. Нехорошо.

2

Другие решения

Что бы ни случилось, вы получите неопределенное поведение, поскольку арифметика указателя определяется только в массиве (включая позицию «один за другим»).

Лучший вопрос может быть:

int test[10];
int * t1 = test+1;
int b = t1[-1];      // Is this defined behaviour?

Ответ на это да. Определение подписки (C ++ 11 5.2.1):

Выражение E1 [E2] идентично (по определению) * ((E1) + (E2))

так что это эквивалентно *((t1)+(-1)), Определение добавления указателя (C ++ 11 5.7 / 5) предназначено для всех целочисленных типов, со знаком или без знака, поэтому ничего не вызовет -1 быть преобразованным в неподписанный тип; поэтому выражение эквивалентно *(t1-1), который четко определен, так как t1-1 находится в пределах массива.

2

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

1

Официальный ответ: поведение не определено. Неофициально вы пытаетесь получить доступ к целому числу до начала массива. Это означает, что вы указываете компьютеру рассчитывать адрес, который предшествует началу массива, на 4 байта (в вашем случае). Будет ли эта операция успешной или нет, зависит от нескольких факторов. Некоторые из них связаны с тем, будет ли массив размещаться в сегменте стека или в сегменте статических данных, где, в частности, будет расположение этого адреса. На машине общего назначения (windows / linux) вы, вероятно, получите в результате значение мусора, но это также может привести к ошибке нарушения памяти, если адрес окажется где-то, к которому у процесса нет доступа. Что может случиться на специализированном оборудовании, можно только догадываться.

1