Почему перекрытие в выражении присваивания должно быть точным, а объекты должны иметь один и тот же тип, и что это означает? - PullRequest
2 голосов
/ 05 августа 2020

Просматривая Enumeration of Core Undefined Behavior , я наткнулся на случай [expr.ass] . Приведен пример:

int x = 1;
char* c = reinterpret_cast<char*>(&x);
x = *c;

Что именно не так с этим кодом? Это потому, что он обращается к x с обеих сторон операнда, но один из них - через указатель псевдонима? Будет ли достаточно этого исправления:

int x = 1;
char* c = reinterpret_cast<char*>(&x);
int y = *c;
x = y;

? Если нет, то действительно ли незаконно получить доступ к любым частям объекта через char* (при условии, что sizeof объекта больше, чем char, ради сохранения "" части"часть)? Если да, то почему сериализация в двоичный код работает, поскольку она основана на присвоении заданному объекту псевдонима с (возможно, cv-квалифицированным) char*, за которым следует отправка (что требует разыменования, аналогично приведенному выше примеру) отдельных байтов в поток?

1 Ответ

1 голос
/ 05 августа 2020

На некоторых платформах, учитывая что-то вроде long *x,*y,*z;, наиболее эффективным способом обработки *x = *y + *z; может быть:

  • Добавить младшее слово *y к младшее слово *z, отмечая перенос, и сохраните результат в младшем слове *x.

  • Добавьте старшее слово *y к старшее слово *z вместе с любым переносом из предыдущего шага и сохраните его в старшем слове *x.

Если младший слово *x совпало со старшим словом *y, выполнение операций в этой последовательности приведет к перезаписи старшего слова *y до того, как оно будет использовано в выражении.

Примечание что с clang и g cc ограничения на перекрытие не ограничиваются примитивными типами. Связанная проблема возникает с конструкцией типа:

struct s { int x[2]; };

int test(struct s *p1, struct s *p2)
{
  if (*(p1->x))
    *(p2->x+1) = 1;
  return *p1->x;
}

Здесь все фактические загрузки и сохранения выполняются путем разыменования указателей типа int*, а не типа struct s*, сгенерированного g cc. код требует, чтобы либо p1, и p2 идентифицировали один и тот же экземпляр struct s, либо непересекающиеся экземпляры и могут работать некорректно, если они идентифицируют перекрывающиеся экземпляры.

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