Как отловить ошибки во время выполнения в C и C ++? - PullRequest
4 голосов
/ 29 июня 2011

Как изменение CONST int,

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

Ответы [ 7 ]

6 голосов
/ 29 июня 2011

Если вы имеете в виду C ++, существует определенный класс исключений с именем runtime_error, который можно перехватить с помощью предложения catch

catch(std::runtime_error& e) {}

Тем не менее, многие вещи в C и C ++ (например, изменение const int) приводят к undefined behvior . Вы не можете поймать их во время выполнения. Вы не можете поймать их. Потому что не генерируется исключение (технически может случиться что угодно, включая выброс исключения (только C ++), но это не то, на что вы можете или должны надеяться)

Решение - написать чистый безопасный код. Для этого есть много советов, перечисленных во многих книгах:)

2 голосов
/ 29 июня 2011

Изменение const, согласно спецификации, является «неопределенным поведением», поэтому компилятор может делать все что угодно.На практике многие реализации иногда генерируют ошибки времени выполнения для такого кода, но многие этого не делают.Это часто зависит от характера программы.Вот иллюстрация:

#include <stdio.h>
#include <string.h>

typedef int (*fn)(const char *);

extern const fn global_fn_ptr;
extern const char global_string[];
const fn global_fn_ptr = puts;
const char global_string[] = "hello";

int main(int argc, char *argv[])
{
    puts("Setting global_fn_ptr to NULL");
    *(fn *)&global_fn_ptr = NULL;
    puts("Setting string to \"bye\"");
    strcpy((char *)global_string, "bye");
    return 0;
}

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

Обычно небезопасно перехватывать SIGBUS или SIGSEGV в C ++ и поворачиватьэто в исключение.Также очень трудно правильно longjmp из обработчика сигнала - половина кода, который использует этот шаблон в C, вероятно, неверна.Самый безопасный вариант - позволить программе немедленно завершиться, или, если вам действительно нужна такая помощь из среды выполнения, работать очень осторожно с кодом C, чтобы вы могли освободить соответствующие ресурсы при нелокальном выходе - C ++ не будет делать, потому что longjmp не будет вызывать деструкторы.

Или вы можете просто перейти на C # или Java, обе из которых имеют среды выполнения, которые делают это для вас, и сборщики мусора, которые впоследствии очищаются.

1 голос
/ 01 июля 2011

Я был совершенно не прав.

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

n1570 , то есть проект комитета для следующей итерации стандарта C, дает правило в разделе 6.7.3, как терпеливо указал @Dietrich Epp.Формулировка в этом разделе, вероятно, не изменилась с C89.

Мне очень жаль, что я утверждаю иначе;и за оскорбление членов этой группы.Особенно Дитрих.

Теперь, где я могу найти эту восхитительную ворону свободного доступа?

1 голос
/ 29 июня 2011

В C ошибки времени обычно генерируют сигналы, которые могут обрабатываться обработчиками сигналов.

В C ++ ошибки времени выполнения могут также генерироваться как исключения, которые могут быть перехвачены в блоке try / catch.

Для продолжения в какой-то момент, а не для сбоя, вам нужно будет использовать setjmp / longjmp в обработчиках сигналов - возвращение после получения сигнала от программной ошибки небезопасно

1 голос
/ 29 июня 2011

Это зависит от операционной системы.Сам язык определяет их как неопределенное поведение.

В POSIX-совместимых операционных системах ваша программа может перехватить сигнал SIGSEGV в случае ограниченного доступа к памяти, SIGILL в случае неверной инструкции или SIGFPE в случае недопустимой операции с плавающей запятой, например деление на ноль.

0 голосов
/ 29 июня 2011

Если я правильно понимаю, то сценарии, о которых вы говорите, это (обычно) неопределенное в зависимости от языка.

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

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

Например, Electric Fence отлично показывает, где вы пишете в память, что вы не должныбыть (хотя не активируйте его в сборках релиза!).Сработает ли это для записи чего-либо, чье const -тирование вы отбросили, будет зависеть от того, какие оптимизации были применены;возможно, что объект будет иметь доступную для записи память, и будет физически невозможно определить, что вы действительно делаете что-то не так.

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

0 голосов
/ 29 июня 2011

Вы должны это знать, и, должно быть, ваш пример плохо рассмотрен, но в любом случае стоит отметить, если кто-то ошибается:или const что-нибудь еще) в время выполнения ;const - это просто время компиляции .Таким образом, нет ошибки времени выполнения для изменения const int.

...