2017-01-31 18 views
1

Я использую strerror_r в функции вспомогательного каротажа. Как описывает справочная страница, существуют две версии этой функции. Версия POSIX возвращает int. Версия GNU возвращает строку (char *).strerror_r неверно объявлено в Alpine Linux

Как таковой, так что мой 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 

Который, кажется, что независимо от того, какая среда компилятора используется, единственная заявленная версия n strerror_r - это версия POSIX, которая возвращает int. Поэтому объясняется, почему произошла ошибка.

Не указывая пользователям, что они могут вручную #undef _GNU_SOURCE или изменить источник, как я могу обойти это, чтобы код мог оставаться портативным? Глобальная неопределенность _GNU_SOURCE скорее всего не стартер, потому что это C++ (и, как упоминалось выше, требуется libstdC++). Я пытаюсь понять, будет ли еще одна комбинация макросов, на которую я мог бы протестировать, но я не могу придумать ничего очевидного.

+0

Официальной макро проверки (по справочной странице Вы связываетесь) является '(_POSIX_C_SOURCE> = 200112L || _XOPEN_SOURCE> = 600) &&! _GNU_SOURCE', чтобы быть правдой, если предоставляется версия POSIX, иначе предоставляется версия GNU. Это означает, что ваш чек должен быть достаточным, чтобы обеспечить версию GNU, а библиотека C в Alpine Linux, похоже, глючит или устарела. –

+0

Оберните его в свою собственную функцию. Сделайте его достаточно гибким, чтобы использовать любой вариант. –

+0

@ н.м. Можете ли вы уточнить? Это уже завернуто в функцию ... – selbie

ответ

5

Вы можете воспользоваться 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); 
+0

Спасибо. Я не знаю, почему я сам об этом не думал. Кажется, сейчас так очевидно. – selbie