Следующий код прекрасно компилируется, например, с настройками по умолчанию в Xcode 11.3.1:
#include <stdio.h>
int main(int argc, const char * argv[]) {
char* thing = "123";
thing[2] = '4';
printf("%s\n", thing);
return 0;
}
Однако во время выполнения код прерывается с EXC_BAD_ACCESS на thing[2] = '4'
. Я предполагаю, что это потому, что память для байтов, представляющих "123"
, скомпилирована в двоичный файл моей программы, который на современном процессоре / ОС помечается как для кода , а не для данных . ( Этот ответ подтверждает, что - не говоря уже о том, что в разборке есть строка leaq 0x4d(%rip), %rsi ; "123"
, передающая указатель на адрес относительно указателя инструкции *1012*!)
Это просто исторический артефакт, который C допускает это, начиная с эпохи самоизменяющегося кода? Я замечаю, что могу также назначить void* x = main;
без каких-либо жалоб на то, что я отменяю модификаторы.
В этом ответе говорится:
Согласно обоснованию C99 В комитете были люди, которые хотели, чтобы строковые литералы были модифицируемыми, поэтому стандарт прямо не запрещает это.
Можно ли еще что-нибудь обсудить по этому поводу? С практической точки зрения, есть ли способ сказать clang и / или g cc to пометить такие назначения (даже если они на самом деле не запрещены) с предупреждением , без компиляции как C ++