я использую strerror_r в функции помощника регистрации. Как описано в справочной странице, есть две версии этой функции. Версия POSIX возвращает int. Версия GNU возвращает строку (char *).
Таким образом, чтобы мой код C ++ был более переносимым, у меня есть блок кода, подобный следующему:
char buffer[1000];
int size = 1000;
int result = 0;
char* msg = buffer;
buffer[0] = '\0';
#ifdef _GNU_SOURCE
msg = strerror_r(err, buffer, size);
#else
result = strerror_r(err, buffer, size);
if (result != 0)
{
sprintf(buffer, "unknown error: %d", err);
}
#endif
LogToFile(msg);
В приведенном выше блоке кода будет использоваться любая из версий strerror_r
в зависимости от наличия _GNU_SOURCE
, который ВСЕГДА устанавливается g ++, потому что libstdc ++ требует этого. На Mac и других версиях Unix будет использоваться версия POSIX.
Теперь этот код работал хорошо в течение долгого времени до сегодняшнего дня. Пользователь пытается скомпилировать мой код на Alpine Linux и сообщил об этой ошибке компилятора сегодня на линии, используя strerror_r
main.cpp:16:21 error: invalid conversion from 'int' to 'char*' [-fpermissive]
Который отображается на эту строку:
#ifdef _GNU_SOURCE
msg = strerror_r(err, buffer, size);
Взяв пик на /usr/include/string.h
На этой платформе раскрывается следующее:
#if defined(_POSIX_SOURCE) || defined(_POSIX_C_SOURCE) \
|| defined(_XOPEN_SOURCE) || defined(_GNU_SOURCE) \
|| defined(_BSD_SOURCE)
...
int strerror_r (int, char *, size_t);
...
#endif
Похоже, что независимо от того, какая среда компилятора используется, единственной объявленной версией strerror_r является версия POSIX, которая возвращает int. Так что это объясняет, почему произошла ошибка.
Без необходимости сообщать пользователям, что они могут вручную #undef _GNU_SOURCE
или измените источник, как я могу обойти это так, чтобы код продолжал быть переносимым? Глобально неопределенный _GNU_SOURCE, вероятно, не является стартовым, потому что это C ++ (и, как уже упоминалось выше, требуется libstdc ++). Я пытаюсь увидеть, будет ли другая макрокоманда, которую я смог бы проверить, но я не могу придумать ничего очевидного.
Вы можете воспользоваться перегрузкой функции C ++:
char* check_error(int result, char* buffer, int err) {
if(result)
sprintf(buffer, "unknown error: %d", err);
return buffer;
}
char* check_error(char* result, char*, int) {
return result;
}
И избавьтесь от условной компиляции в использовании:
char buffer[1000];
buffer[0] = '\0';
char* msg = check_error(strerror_r(err, buffer, sizeof buffer), buffer, err);
LogToFile(msg);
Других решений пока нет …