2013-05-15 2 views
0

допустим у меня есть:C++ массив доступа

int test[10]; 

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

int b = test[-1]; 

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

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

int b = *(test - 1); 

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

int b = *(test + 0xFFFFFFFF); 

0xFFFFFFFF является дополнением представление этих двух по десятичной -1

+0

Это неопределенное поведение. – juanchopanza

+0

@ alex23: Это неопределенное поведение на C99 также. Ответы в связанном с вами вопросе не противоречат этому, и эти ответы будут одинаково применимы к C++. –

ответ

2

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

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

1

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

1

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

2

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

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

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

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

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

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