Арифметика указателей в границах c и массива - PullRequest
6 голосов
/ 17 марта 2011

Я просматривал веб-страницу , на которой были некоторые c часто задаваемые вопросы, я нашел это заявление сделанным.

Аналогично, если a имеет 10 элементов и ip указывает на [3], , который вы не можете вычислить или доступ по ip + 10 или ip - 5. (есть один особый случай: вы можете, в этом случай, вычислить, но не доступ, указатель на несуществующий элемент сразу за концом массива, в данном случае это & ​​a [10].

Я был смущен заявлением

Вы не можете вычислить IP + 10

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

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

#include <stdio.h>                                                                                                                                                                  

int main()                                                                                                                                                                          
{                                                                                                                                                                                   
        int a[10], i;                                                                                                                                                               
        int *p;                                                                                                                                                                     

        for (i = 0; i<10; i++)                                                                                                                                                      
                a[i] = i;                                                                                                                                                           

        p = &a[3];                                                                                                                                                                  

        printf("p = %p and p+10 = %p\n", p, p+10);                                                                                                                                  
        return 0;                                                                                                                                                                   
}                     

$ ./a.out                                                                                                                                     
p = 0xbfa53bbc and p+10 = 0xbfa53be4     

Мы можем видеть, что p + 10 указывает на 10 элементов (40 байт) после p. Так что же конкретно означает заявление, сделанное на веб-странице? Я что-то неправильно истолковал.

Даже в K & R (A.7.7) это утверждение сделано:

Результатом оператора + является сумма операндов. Указатель на объект в массиве и значение любого интегральный тип может быть добавлен. ... сумма указатель того же типа, что и оригинальный указатель и указывает на другой объект в том же массиве, соответственно смещение от оригинала объект. Таким образом, если P является указателем на объект в массиве, выражение P + 1 указатель на следующий объект в массив. Если указатель суммы указывает за пределами массива, кроме как в первом месте за высокий конец, результат не определено.

Что значит быть «неопределенным». Означает ли это, что сумма будет неопределенной, или это означает, что только когда мы разыменовываем ее, поведение не определено. Является ли операция неопределенной, даже если мы не разыменовываем ее и просто вычисляем указатель на элемент вне границ.

Ответы [ 3 ]

9 голосов
/ 17 марта 2011

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

В этом конкретном случае, да, стандарт C говорит, что даже вычисление адреса указателя вне допустимых границ массива, без разыменования его, является неопределенным поведением. Это объясняется тем, что существуют некоторые тайные системы, в которых выполнение таких вычислений может привести к некоторой неисправности. Например, у вас может быть массив в самом конце адресуемой памяти, а создание указателя за его пределами вызовет переполнение в специальном регистре адресов, которое генерирует ловушку или ошибку. Стандарт C хочет разрешить такое поведение, чтобы быть максимально переносимым.

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

4 голосов
/ 17 марта 2011

Формулировка веб-страницы запутанная, но технически правильная.Спецификация языка C99 (раздел 6.5.6) обсуждает аддитивные выражения, включая арифметику указателей.Подпункт 8, в частности, гласит, что вычисление указателя за концом массива не должно вызывать переполнение, но помимо этого поведение не определено.

В более практическом смысле компиляторы C, как правило, позволяют вам избежать неприятностей сэто, но что вы делаете с полученным значением, зависит от вас.Если вы попытаетесь разыменовать результирующий указатель на значение, как заявляет K & R, поведение не определено.

Undefined, в терминах программирования, означает «Не делай этого».По сути, это означает, что спецификация, которая определяет, как работает язык, не определяет соответствующее поведение в этой ситуации.В результате теоретически может произойти все что угодно.Как правило, все, что происходит, это то, что у вас в программе есть ошибка, связанная с молчанием или шумом (segfault), но многие программисты любят шутить по поводу других возможных результатов, вызывающих неопределенное поведение, например удаление всех ваших файлов.

2 голосов
/ 17 марта 2011

Поведение будет неопределенным в следующем случае

int a[3];
(a + 10) ; // this is UB too as you are computing &a[10]
*(a+10) = 10; // Ewwww!!!!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...