В следующем коде *(long*)0=0;
используется вместе с предложением if
, но в чем его цель?
if(r.wid*r.ht < tot)
*(long*)0=0;
В следующем коде *(long*)0=0;
используется вместе с предложением if
, но в чем его цель?
if(r.wid*r.ht < tot)
*(long*)0=0;
Он записывает 0 в 0, интерпретируемый как адрес long
, то есть указатель NULL
. Это неправдоподобно, поскольку NULL
никогда не является адресом, на котором вы можете иметь достоверные данные, доступ к которым может получить ваша программа. Этот код вызывает поведение undefined; вы не можете полагаться на него, чтобы иметь какой-то конкретный эффект в целом.
Однако часто такой код используется для принудительной сбой segmentation fault, что иногда удобно отбрасывать в отладчик.
Опять же, это поведение undefined; нет гарантии, что это вызовет такую ошибку, но в системах с дефектами сегментации вышеуказанный код, скорее всего, будет генерировать один. В других системах это может сделать что-то совершенно другое.
Если вы получаете segfault, иногда удобнее запускать его таким образом, чтобы вручную установить точку останова в отладчике. Например, если вы не используете IDE, часто проще вводить эти несколько токенов в код в нужном месте, чем давать отладчику (текстовую) команду, указывая точный файл исходного кода и номер строки вручную может быть немного раздражающим.
В учебнике C abort
есть способ умышленного сбоя программы. Однако, когда вы программируете рядом с металлом, вам, возможно, придется беспокоиться о возможности abort
не работать так, как предполагалось! Стандартная реализация POSIXy abort
вызывает getpid
и kill
(через raise
), чтобы доставить SIGABRT
к процессу, что, в свою очередь, может привести к выполнению обработчика сигнала, который может делать по своему усмотрению. Возможны ситуации, например. глубоко в кишках malloc
, в ответ на катастрофическое, возможно, сокрушительное повреждение памяти, когда вам нужно принудительно вызвать сбой, не касаясь стека вообще (в частности, без выполнения команды возврата, которая может перейти на вредоносный код). *(long *)0 = 0
не самая сумасшедшая вещь, чтобы попытаться в этих обстоятельствах. Он все еще рискует выполнить обработчик сигналов, но это неизбежно; нет способа вызвать SIGKILL
без вызова функции. Более серьезно (IMHO) современные компиляторы, скорее всего, это заметят, заметили, что он имеет поведение undefined, удаляет его и также удаляет тест, потому что тест не может быть когда-либо прав, потому что никто не будет намеренно вызывают поведение undefined, не так ли? Если такая логика кажется порочной, прочитайте раздел LLVM в разделе undefined поведение и оптимизация (часть 2, часть 3).
Есть лучшие способы достижения этой цели. Многие компиляторы в настоящее время имеют встроенный (например, gcc, clang: __builtin_trap()
), который генерирует машинную команду, которая гарантированно приведет к сбою оборудования и доставке SIGILL
; в отличие от трюков undefined с указателями, компилятор не будет оптимизировать это. Если ваш компилятор не имеет этого, но имеет сборные вставки, вы можете вручную вставить такую инструкцию - это, вероятно, достаточно низкий уровень кода, что дополнительный бит машинной зависимости не имеет большого значения. Или вы можете просто позвонить _exit
. Это, пожалуй, самый безопасный способ воспроизвести его, потому что он не рискует работать с обработчиками сигналов, и он не возвращает никаких функций даже внутри. Но это означает, что вы не получаете дамп ядра.
Чтобы программа "выходила ненормально", используйте функцию abort()
(http://pubs.opengroup.org/onlinepubs/9699919799/functions/abort.html).
Стандартная идиома C/С++ для "если условие X неверно, сделать программу анонимно" - это макрос assert()
. Код выше был бы лучше написан:
assert( !(r.wid*r.ht < tot) );
или (если вы с удовольствием игнорируете случаи краев), он читается более чисто:
assert( r.wid*r.ht >= tot );
Если ширина разницы в высоте r меньше, чем общая, выполните сбой программы.