Можете ли вы разработать простой макрос для эффективной выдачи ошибки компилятора при использовании? - PullRequest
2 голосов
/ 25 января 2012

Я специально ищу странное определение макроса: мне нужен макрос, определенный таким образом, чтобы в случае, если макрос эффективно использовался в скомпилированном коде, компилятор неизменно выдавал ошибку.

Предыстория: поскольку C11 ввел несколько новых ключевых слов, а новый стандарт C ++ 11 также добавил несколько, я хотел бы добавить файл заголовка в мои проекты (в основном с использованием компиляторов C89 / C95 с несколькими дополнениями) заставить разработчиков воздерживаться от использования этих новых ключевых слов в качестве имен идентификаторов, если, конечно, они не распознаются в качестве ключевых слов по назначению.

В древнем прошлом я делал это для new так:

#define new *** /* C++ keyword, do not use */

И да, это сработало. Пока этого не произошло, когда программист забыл подчеркивание в имени параметра:

void myfunction(uint16_t new parameter);

С тех пор я использовал варианты, но мне никогда больше не бросали вызов.

Теперь я намереваюсь создать файл со всеми ключевыми словами, не поддерживаемыми различными компиляторами, и я ищу надежное решение, в лучшем случае с не слишком запутанным сообщением об ошибке. «Синтаксическая ошибка» была бы в порядке, но «отсутствующий параметр» уже сбивал бы с толку.
Я думаю, что это похоже на

#define atomic +*=*+ /* C11 derived keyword; do not use */

и, кроме моих обычных колебаний, я вполне уверен, что любое использование (но не определение) макроса приведет к ошибке.

РЕДАКТИРОВАТЬ: Чтобы сделать это еще сложнее, MISRA будет разрешать использовать только базовый набор символов источника и выполнения, поэтому @ или $ не допускаются.

Но я хотел бы спросить сообщество: у вас есть лучшая макроэкономическая ценность? Как эффективно, но короче? Или даже дольше, но более надежным в какой-то странной ситуации? Или совершенно другой метод генерации ошибки (только с использованием компилятора, а не внешних инструментов!), Когда для каких-либо целей используется «обескураженный» идентификатор?

Отказ от ответственности: И да, я знаю, что могу использовать grep или парсер для запуска на ночной сборке и сообщать о найденных предупреждениях. Но удаление немедленной ошибки на столе разработчиков происходит быстрее, и ее обязательно нужно исправить до регистрации.

Ответы [ 5 ]

2 голосов
/ 25 января 2012

Если для спорта используется самая короткая последовательность символов, которая всегда выдает ошибку, любая комбинация из двух 1-символьных операторов, которые не могут встречаться по закону вместе, но

  • , не использует ({ или}) потому что gcc имеет для этого особое значение
  • не используйте какие-либо несбалансированные скобки, потому что они могут увести вас далеко, пока ошибка не будет распознана
  • не используйте < или > потому что они могут соответствовать параметрам шаблона для C ++
  • не использовать префиксные операторы в качестве второго символа
  • не использовать постфиксные операторы в качестве первого символа

Это оставляет некоторые возможности

  • .., .| и другие комбинации с ., поскольку . ожидает следующий идентификатор
  • &|, &/, &^, &,, &;
  • !|, !/, !^, !,, !;

Но на самом делеболее дружественный к пользователю, я бы сначала поместил в него _Pragma, чтобы компилятор также выдавал предупреждение.

#define atomic _Pragma("message \"some instructive text that you should read\"") ..
2 голосов
/ 25 января 2012
#define atomic do not use atomic

Расширение не является рекурсивным, поэтому оно останавливается.Единственный способ предотвратить ошибку компиляции:

#define do
#define not
#define use

, но это вербено, потому что do и not являются ключевыми словами.

Сообщение об ошибке может даже включать «атомарный».Вы можете увеличить вероятность этого, перефразировав сообщение:

#define atomic atomic cannot be used

(хотя теперь вы не играете с ключевыми словами в сообщении.)

2 голосов
/ 25 января 2012

Я думаю, вы можете просто использовать недопустимый символ:

#define bad_name @

Еще один способ, который будет работать, будет следующим:

static const char *illegal_keyword = "";

#define bad_name (illegal_keyword = "bad_name")

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

Line 8: error: called object 'illegal_keyword = "printf"' is not a function

И последнее, возможно, самое короткое и всегда будет работать, это:

#define bad_name #

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

1 голос
/ 25 января 2012

Моя попытка:

#define new new[-1]
#define atomic atomic[-1]
1 голос
/ 25 января 2012

Я думаю, [[]] не является допустимой последовательностью токенов, поэтому вы можете использовать это:

#define keyword [[]]

Ошибка будет синтаксической ошибкой с жалобами на [ или ].

...