C ++ Увеличение указателя на неизвестную область памяти - PullRequest
2 голосов
/ 18 февраля 2011

У меня есть запрос о поведении C / C ++, касающемся слепого увеличения указателя.

Итак, у меня есть указатель на int как параметр для функции

func(int* thePointer) {...

и у меня есть цикл внутри этой функции

while(*thePointer) {
    ++thePointer;
}

Я понимаю, что до тех пор, пока в памяти за указателем есть int, цикл будет продолжаться, но что, если память принадлежит части памяти другого типа? Скажем, вы увеличиваете первые 4 байта double. Будет ли int иметь значение / цикл продолжится в этом случае?

Отказ от ответственности: я знаю, что это, скорее всего, плохая практика. Это чисто академический вопрос.

Ответы [ 7 ]

7 голосов
/ 18 февраля 2011

В памяти нет такой вещи как int или double .Память - это просто память: заполнитель для байтов.

Итак, если вы продолжите увеличивать указатель до int , вы укажете на следующие четыре байта в памяти и все.Если вы попытаетесь использовать эту часть памяти через указатель на целое число, вы, вероятно, будете обращаться с ее содержимым, как если бы оно было int .

В конечном итоге вы укажете на областьпамять не назначена вашему процессу, и ваша программа завершит работу с SEGMENTATION FAULT .

4 голосов
/ 18 февраля 2011

ISO 14882, раздел 5.7:

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

$ 5 Когда выражение с целочисленным типом добавляется или вычитается из указателя, результат имеет тип операнда указателя.Если операнд-указатель указывает на элемент объекта массива, а массив достаточно велик, результат указывает на смещение элемента от исходного элемента, так что разность индексов результирующего и исходного элементов массива равна интегральному выражению.Другими словами, если выражение P указывает на i-й элемент объекта массива, выражения (P) + N (эквивалентно, N + (P)) и (P) N (где N имеет значение n) указывают соответственноэлементы i + nth и i - nth объекта массива, если они существуют.Кроме того, если выражение P указывает на последний элемент объекта массива, выражение (P) +1 указывает один за последним элементом объекта массива, а если выражение Q указывает на один последний элемент последнего элемента массива,выражение (Q) 1 указывает на последний элемент объекта массива.Если и операнд-указатель, и результат указывают на элементы одного и того же объекта массива или один после последнего элемента объекта массива, оценка не должна вызывать переполнение;в противном случае поведение не определено.

2 голосов
/ 18 февраля 2011

но что, если память принадлежит к части другого типа памяти?Скажем, вы увеличиваете в первые 4 байта двойного.Будет ли int иметь значение / цикл продолжится в этом случае?

Компилятору все равно, какой тип памяти там.Вы можете увеличить любой тип памяти, который вы выберете, и все будет в порядке.

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

Пока память в этом месте принадлежит вам (то есть: ваша программа выделяла ее), вы сможете установить его.При этом, если местоположение памяти не было чем-то, что вы рассматривали как целочисленное значение, вы, скорее всего, испортили бы состояние какого-либо другого объекта, что в конечном итоге приведет к возникновению плохих вещей.

1 голос
/ 18 февраля 2011

Перемещение указателя опасно, если вы обращаетесь к памяти (чтение или запись).

Перемещение указателя за конец текущего объекта и разыменование объекта - неопределенное поведение.

Один объект:

int  x;
int* xp = &x;

xp++; // Now pointing past the object.
int  y  = *xp; // Undefined behavior.

Массив:

int  x[10];
int  xp = x;

while(*xp)
{   ++xp;  // Works fine the first 9 times.
}          // After that it is UB to access the memory pointed at by xp

Примечание: в цикле

while(*xp)  // This continues while the memory pointed at
            // is not zero. As soon as a zero is found in memory
            // the loop exits.
1 голос
/ 18 февраля 2011

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

0 голосов
/ 18 февраля 2011

Приведенный выше код не имеет никакого отношения к количеству int s в памяти.Ваш код работает до тех пор, пока не найдет эквивалент целого числа, установленного на ноль.

Да, это очень плохая практика.Результаты не определены.Вы, скорее всего, столкнетесь с памятью, которая не является частью ожидаемого массива.И у вас есть высокая вероятность того, что вы попадете в память, которая вызывает сбой процессора.

0 голосов
/ 18 февраля 2011

Если вы продолжите увеличиваться, в конечном итоге вы получите SIGSEGV или моральный эквивалент Windows. Тем не менее, прежде чем попасть туда, вы, скорее всего, совершите Тур Кука о том, что еще лежит в ВМ. Другие переменные, бывшие в употреблении обертки для сэндвичей, что угодно.

Подобные циклы - это не просто «плохая практика», это основной источник эксплойтов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...