Дамп ядра на типе указателя-приведение (int к double) в C
Я наткнулся на этот фрагмент кода:
void incme(double *p)
{
*p += 1;
}
int i = 1;
incme((double *)&i); /* WRONG */
Когда я пытаюсь выполнить его,я получаю дамп ядра. Что не так с этим кодом? Мы не можем ввести приведение указателя int к типу double.
Спасибо.
6 ответов:
Вы не бросаете
int
вdouble
, вы бросаетеint *
вdouble *
. Это небезопасно, еслиsizeof(double)
иsizeof(int)
не одно и то же...Даже если вы сопоставите размеры хранилища, что вы ожидаете получить на выходе? Типы с плавающей запятой и целые числа, как правило, не имеют каких-либо совместимых представлений.
(int)
обычно выравнивается до 4 байт на 32-битном оборудовании, в то время как(double)
обычно должен быть выровнен по 8 байтам. Если вашi
не находится на 8-байтовом выровненном адресе, вы можете ожидатьSIGBUS
; Кроме того, если он выделен в стеке, более крупный(double)
, вероятно, перезапишет фрейм вызова, ведущий к дампу ядра, когдаincme()
вернется, если предыдущий не убьет его.
Можно привести любой указатель из одного типа в любой другой тип, но это не делает его правильным. В этом случае, если sizeof (double)!= sizeof (int), то строка в "incme", скорее всего, будет записываться в память вне той, которая выделена целому числу "i". Тогда все ставки отменяются.
Существует разница между преобразованием типа и реинтерпретацией памяти .
Ваш код принудительно преобразует указатель типа
int *
В Типdouble *
. Это достигается с помощью явного приведения. Само по себе это действие не обязательно приводит к каким-либо проблемам. Итак, предположение, которое вы сделали в названии вашего вопроса, неверно. "Сброс ядра", который вы наблюдаете, не имеет ничего общего с самим броском.Как только вы выполнили преобразование, вы перейдите к разыменованию результирующего указателя и получите доступ (измените) к памяти, на которую он указывает. Вот тогда-то и возникает настоящая проблема. Код выполняет реинтерпретацию данных : он пытается получить доступ к объекту типа
Итак, краткий ответ на ваш вопрос таков: Вы можете определенно бросить указатель, который указывает на объектint
как к объекту типаdouble
. Это всегда явно незаконно в языке Си. Сбой, который вы наблюдаете, вызван именно этой попыткой переосмысления.int
типаdouble *
. Но Вы не можете разыменовать результирующий указательdouble *
и получить доступ к памяти, как если бы она содержала объектdouble
.