В макросе envSet (имя) GNU C, что означает (void) "" имя?

Сегодня я столкнулся с этим синтаксисом и не мог понять, что это значит:

// Uses the GNU C statement expression extension
#define envSet(name) ({ \
static int initialised; \
static bool set; \
(void) "" name; \
if (!initialised || !g_cacheEnv) { \
    const char *value = getenv(name); \
    set = value != NULL; \
    initialised = true; \
} \
set; \
})

Конкретная строка, которую я не могу понять, это:

(void) "" name; \

Может ли кто-нибудь пролить свет на это?

Ответ 1

Это похоже на способ статически гарантировать, что name является строковым литералом, а не каким-либо другим типом.

Если вы выполняете (void)"" "hello";, то это действительное выражение C.

Но если вы сделаете что-то вроде (void)"" 1;, вы получите синтаксическую ошибку.

Ответ 2

Два последовательных строковых литерала конкатенируются. Предположительно, он проверяет, является ли name строковым литералом. Если это не так, компилятор сообщит об ошибке.

(void) cast будет подавлять предупреждения типа "выражение без эффекта".

Ответ 3

Посмотрев на код, я считаю, что цель состоит в том, чтобы он вызывал getenv при первом вызове, кэшировал результат, а затем после этого использовал кешированный результат без необходимости называть getenv больше. Если getenv используется со строковым литералом, то все последующие вызовы будут запрашивать одну и ту же переменную среды; если ничто не может изменить эту переменную среды, они, следовательно, возвратят тот же результат. Если в коде был указан указатель на строку, которая впоследствии была изменена, результат кэширования, скорее всего, не был бы правильным для новой строки, поэтому цель трюка - убедиться, что этого не произойдет.

Поскольку для каждого строкового литерала, который может быть использован, потребуется связанная с ним связанная с ним статическая переменная, указанный фрагмент кода не может быть разумно превращен в функцию. С другой стороны, количество кода, необходимого для каждого повторения, выглядит немного. Кроме того, если одна и та же переменная тестируется более чем в одном месте в коде, каждый может иметь свой собственный набор переменных и код проверки среды.

В зависимости от того, как будет использоваться эта функция, она может оказаться намного быстрее, чем код, который должен проверять переменную окружения каждый раз, когда он вызывается, и может использоваться из функции, вызываемой в цикле без предварительного setup (если код клиента называется функцией "предварительной настройки", там должен быть проверен поиск имени, устраняя необходимость проверки внутри цикла, чтобы проверить, был ли поиск выполнен).