Нарушение доступа вызвано тем, что 0x87E64A05
больше, чем наибольшее значение, которое может содержать 32-разрядное целое число со знаком (которое составляет 0x7FFFFFFF
).
Поскольку int
, скорее всего, 32-разрядное, то XREFKILLER
не можетудерживайте 0x87E64A05
, и поэтому его значение будет определяться реализацией.
Это значение затем используется позже для повторного вычитания из xs
после того, как переданный указатель был искусственно продвинут литерал 0x87E64A05
, который будет интерпретироваться как long
или long long
для подгонки значения в зависимости от того, является ли long
32-битным или большим, и поэтому не будет сужаться до значения, определенного реализацией.
Поэтому выфактически остаются с некоторым случайным указателем в xs[i - XREFKILLER]
, и это может привести к неопределенному поведению, например, к нарушению доступа.
Если скомпилировано для 32-битного x86, вероятно, так получится, что int
и указатели имеют один и тот же бит-size и что поведение, определяемое реализацией, чрезмерное / недостаточное и сужающее поведение оказываются такими, что сложение и вычитание отменяют корркак и ожидалось.Однако, если тип указателя больше 32 бит, он не может работать.
Нет никакого смысла в XREFKILLER
.Он просто выполняет одно вычисление, которое немедленно возвращается (если нет переполнения / недополнения).
Обратите внимание, что тот факт, что компилятор вообще принимает сужение в аргументе шаблона, является ошибкой.Ваша программа некорректна, и компилятор должен выдать вам сообщение об ошибке.Например, в GCC эта ошибка сохраняется до версии 8.2, но была исправлена в текущей транке (то есть в версии 9).
У вас будут похожие проблемы с XORSTART
, если char
окажется signed
на вашей платформе, потому что тогда указанные вами значения не будут вписываться в нее.Но в этом случае вы должны будете включить предупреждения, потому что это не будет преобразованием, делающим программу плохо сформированной.Также поведение ^
может быть не таким, как вы ожидаете, если char
равно signed
в вашей системе.
Не ясно, какой смысл
s[BUFLEN - 1] = (2 * 2 - 3) - 1;
является.Это должно быть:
s[BUFLEN - 1] = '\0';
Передача результирующей строки в printf
в качестве первого аргумента приведет к ложному неопределенному поведению, если полученная строка будет содержать %
, что будет интерпретировано как введениев спецификатор формата.Используйте std::cout
.
Если вы хотите использовать printf
, вам нужно написать std::printf
и #include<cstdio>
, чтобы гарантировать его доступность.Однако, поскольку это C ++, вы все равно должны использовать std::cout
.
Более существенно, что ваша выходная строка может содержать 0
, отличную от завершающей после преобразования.Это будет интерпретироваться как конец строки в стиле C.Это кажется серьезным недостатком дизайна, и вы, вероятно, захотите использовать std::string
вместо этого по этой причине (и потому что это лучший стиль).