Когда символ* безопасен для строгого искажения указателя?

NullPointerException s - исключения, возникающие при попытке использовать ссылку, которая указывает на отсутствие местоположения в памяти (null), как если бы она ссылалась на объект. Вызов метода по нулевой ссылке или попытка получить доступ к полю нулевой ссылки вызовет функцию NullPointerException. Они наиболее распространены, но другие способы перечислены на странице NullPointerException javadoc.

Вероятно, самый быстрый пример кода, который я мог бы придумать для иллюстрации NullPointerException, be:

public class Example {

    public static void main(String[] args) {
        Object obj = null;
        obj.hashCode();
    }

}

В первой строке внутри main я явно устанавливаю ссылку Object obj равной null. Это означает, что у меня есть ссылка, но она не указывает на какой-либо объект. После этого я пытаюсь обработать ссылку так, как если бы она указывала на объект, вызывая метод на нем. Это приводит к NullPointerException, потому что нет кода для выполнения в местоположении, на которое указывает ссылка.

(Это техничность, но я думаю, что она упоминает: ссылка, которая указывает на null, равна 't то же, что и указатель C, указывающий на недопустимую ячейку памяти. Нулевой указатель буквально не указывает на в любом месте , который отличается от указаний на местоположение, которое оказывается недопустимым.)

23
задан cokeman19 13 November 2017 в 02:13
поделиться

2 ответа

Ре @Adam Розенфилд: объединение достигнет выравнивания, пока поставщик символа* начал делать что-то подобное.

может быть полезно отступить и выяснить то, о чем это - все.

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

Рассмотрение, что компиляторы часто имеют опции для управления, как все это обрабатывается, или нет, Вы видите, что существует много способов, которыми могут произойти неожиданности. Это особенно важно для знания, когда передающие указатели на структуры (бросок как символ* или не) в библиотеки, которые были скомпилированы для ожидания различных соглашений выравнивания.

Что относительно символа*?

предположение о символе* - то, что sizeof (символ) == 1 (относительно размеров всех других значительных данных) и что символ* указатели не имеет никакого требования выравнивания. Таким образом, подлинный символ* может всегда безопасно раздаваться и использоваться успешно без беспокойства о выравнивании, и это идет для любого элемента символа [] массив, работая ++ и - на указателях, и так далее. (Странно, пусто* не совсем то же.)

Теперь необходимо быть в состоянии видеть, как при передаче своего рода данных структуры в символ [] массив, который не был самостоятельно выровнен соответственно, пытаясь вспомнить указатель, который действительно требует, выравнивание (выравнивание) может быть серьезной проблемой.

при создании объединения символа [] массивом и структурой больше всего требовательное выравнивание (т.е. та из структуры) будет соблюдать компилятор. Это будет работать, если поставщик и потребитель будут эффективно использовать соответствие объединениям так, чтобы кастинг структуры* для обугливания* и назад работал просто великолепно.

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

7
ответ дан orcmid 29 November 2019 в 03:08
поделиться

Корректный, второй пример нарушает строгие правила искажения, поэтому если Вы компилируете с эти -fstrict-aliasing флаг, существует шанс, можно получить неправильный объектный код. Полностью правильное решение должно было бы использовать объединение здесь:

union
{
  SocketMsgToRecv msg;
  char msgBuff[100];
};

recv(socket, msgBuff, 100);

printf("Got Msg: a: %i, b: %i", msg.a, msg.b);
6
ответ дан Adam Rosenfield 29 November 2019 в 03:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: