(комментарии к вопросу объясняют, что мы говорим о зарезервированных идентификаторах в смысле раздела 7.1.3 C99, т. Е. Идентификаторах, совпадающим с /^_[A-Z_]/
в любом месте, /^_/
в области видимости файла, /^str[a-z]/
с внешней связью и т. Д. Итак, вот мое предположение, по крайней мере, часть того, что вы спрашиваете ...)
Они не зарезервированы в том смысле, что (любой конкретный этап) компилятор должен диагностировать их неправильное использование. Скорее, они зарезервированы в том, что если вы достаточно глупы, чтобы (неправильно) использовать их самостоятельно, вы не будете жаловаться, если ваша программа перестанет работать или перестанет компилироваться позднее.
Мы все видели, что происходит, когда люди с опасным объемом знаний заглядывают в системные заголовки и затем пишут свои собственные средства защиты заголовков:
#ifndef _MYHEADER_H
#define _MYHEADER_H
// ...
#endif
Они вызывают неопределенное поведение, но ничто не диагностирует это как " ошибка: зарезервированный идентификатор, используемый кодом конечного пользователя ". Вместо этого в основном им везет, и все хорошо; но иногда они сталкиваются с идентификатором, представляющим интерес для реализации, и происходят запутанные вещи.
Точно так же у меня часто есть внешне видимая функция с именем strip()
или около того:
char *strip(char *s) {
// remove leading whitespace
}
При чтении 7.1.3, 7.26 и 7.26.11 в C99 это вызывает неопределенное поведение. Однако я решил не заботиться об этом. Идентификатор не зарезервирован в том смысле, что сегодня может произойти что-то плохое, но потому что Стандарт оставляет за собой право изобретать новую стандартную подпрограмму str-ip()
в будущем пересмотре. И я решил, что string - ip
, каким бы оно ни было, является маловероятным именем для строковой операции, которая будет добавлена в будущем - поэтому в этом маловероятном случае я Я перейду этот мост, когда доберусь до него. Технически я использую неопределенное поведение, но не ожидаю, что его укусят.
Наконец, контрпример к вашей точке 4:
#include <string.h>
#define memcpy(d,s,n) (my_crazy_function((n), (s)))
void foo(char *a, char *b) {
memcpy(a, b, 5); // intends to invoke my_crazy_function
memmove(a, b, 5); // standard behaviour expected
}
Это соответствует вашим 4.1, 4.2, 4.3 (если я понимаю ваше намерение по этому последнему). Однако, если memmove
дополнительно реализован как макрос (через 7.1.4 / 1), который написан в терминах memcpy
, тогда у вас будут проблемы.