Доступ к массиву с отрицательным числом! - PullRequest
14 голосов
/ 14 сентября 2009

Я конвертирую чрезвычайно большую и очень старую (25 лет!) Программу из C в C ++.

В нем есть много (очень очень много) мест, где я обращаюсь к глобальному одномерному массиву UBYTE, используя различные целочисленные индексы. Иногда этот индекс может быть отрицательным.

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

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

Так что мой вопрос сейчас таков: есть ли способ во время выполнения для меня обнаружить какие-либо случаи доступа к массивам с отрицательными индексами? Я буду впечатлен, если кто-нибудь может придумать ответ. Если вы уверены, что это невозможно сделать каким-либо автоматическим способом, то скажите мне, что это тоже ценная информация.

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

Ответы [ 9 ]

26 голосов
/ 14 сентября 2009

Можете ли вы заменить глобальный одномерный массив ubyte объектом с перегруженным оператором []? Использование абсолютного значения для ввода int может решить некоторые ваши проблемы.

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

6 голосов
/ 14 сентября 2009

Знаете ли вы границы индексов?

Читая комментарий под ответом Сийфиона, кажется, что в вашей проблемной области допустимы отрицательные индексы, и поэтому нет смысла пытаться заставить все индексы быть положительными. Лучшее решение - разрешить отрицательные индексы без нарушения каких-либо языковых правил (что, кстати, и ваша C-версия сделала. Вам просто повезло, что она не взорвалась;))

Так что, если вы знаете, что индексы, которые вы собираетесь использовать, находятся в диапазоне от -x до y, просто создайте массив размером x + y и используйте указатель на x-й элемент при доступе к массиву.

Например, если вам нужен массив с индексами от -4 до 5:

int arr[10];
int* ptr = arr+4;
// use ptr when you need to index into the array:

ptr[-4]; // is valid, reads arr[0]
ptr[5]; // is valid, reads arr[9]

Конечно, то же самое можно было (и нужно) сделать в C.

Еще один совет - не обращаться напрямую к необработанному массиву. Вместо этого определите простые функции доступа. (например, но не обязательно, помещая массив в класс. Если вы поместите его в класс, вы можете перегрузить оператор [], чтобы он даже выглядел как массив по-прежнему)

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

4 голосов
/ 14 сентября 2009

Может сработать какой-то тип проверки памяти, особенно если вы можете принудительно установить массив на своей странице. Я бы использовал valgrind в Linux, не уверен, что вы будете использовать в Windows - purify?

3 голосов
/ 14 сентября 2009

Есть ли способ, во время выполнения, для меня обнаруживать любые случаи доступа массивы с отрицательными индексами?

Замените ваш глобальный массив на std :: vector . Заменить использование синтаксиса array[index] на

vector.at(index)

Это делает именно то, что вы просите: он добавляет проверки, связанные с массивом времени выполнения.

3 голосов
/ 14 сентября 2009

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

2 голосов
/ 14 сентября 2009

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

1 голос
/ 14 сентября 2009

Лично я бы попытался выяснить, почему любой из ваших индексов может быть отрицательным; очевидно, что они вернут неправильное значение, так что, конечно, вы не должны допустить, чтобы индекс стал отрицательным?

Исправьте код, который позволяет им идти в отрицательном направлении, вместо того, чтобы пытаться вставить квадратную пробку в круглое отверстие (так сказать);)

0 голосов
/ 28 марта 2013

Посмотрите этот пример по MSDN:

Положительные и отрицательные индексы

0 голосов
/ 14 сентября 2009

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

a [-i] = * (a-i)

поэтому начните с (a-i) в качестве базового адреса вместо (a), чтобы вы просто сместили массив и получили желаемые значения.

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