2015-12-15 3 views
2

Вот моя программа.Почему strerror_r ведет себя по-разному при компиляции с помощью стандартов gnu90 и c90?

#include <stdio.h> 
#include <string.h> 
#include <stdlib.h> 
#include <errno.h> 

int main() 
{ 
     char errbuf[256]; 

     errno = 0; 
     strtoul("99999999999999999999999999999999999999999999", NULL, 0); 
     strerror_r(errno, errbuf, sizeof errbuf); 
     printf("strerror_r: %s\n", errbuf); 

    return 0; 
} 

Когда я скомпилировать его с -std=gnu90 или -std=gnu99, я получаю ожидаемый выход.

[email protected]:~/lab/linux$ rm -f a.out && gcc -std=gnu90 -Wall -Wextra -pedantic foo.c && ./a.out 
strerror_r: Numerical result out of range 
[email protected]:~/lab/linux$ rm -f a.out && gcc -std=gnu99 -Wall -Wextra -pedantic foo.c && ./a.out 
strerror_r: Numerical result out of range 

Но когда я скомпилировать его с -std=c90 или -std=c99, я получаю предупреждение, и я не вижу strerror_r положить строку в errbuf.

[email protected]:~/lab/linux$ rm -f a.out && gcc -std=c90 -Wall -Wextra -pedantic foo.c && ./a.out 
foo.c: In function ‘main’: 
foo.c:12:2: warning: implicit declaration of function ‘strerror_r’ [-Wimplicit-function-declaration] 
    strerror_r(errno, errbuf, sizeof errbuf); 
^
strerror_r: 
[email protected]:~/lab/linux$ rm -f a.out && gcc -std=c99 -Wall -Wextra -pedantic foo.c && ./a.out 
foo.c: In function ‘main’: 
foo.c:12:2: warning: implicit declaration of function ‘strerror_r’ [-Wimplicit-function-declaration] 
    strerror_r(errno, errbuf, sizeof errbuf); 
^
strerror_r: 

Что происходит неправильно, когда я использую -std=c90 или -std=c99?

+1

В [N1256] не найдено определения 'strerror_r' (http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf). – MikeCAT

ответ

5

С помощью -std=c89 вы просите реализацию предоставить исключительно декларации для идентификаторов, относящихся к ISO 9899: 1989. Идентификатор strerror_r не является частью C89 (или C99), поэтому прототипа нет. В результате вы получаете предупреждение о неявной декларации.

Если вы посмотрите на соответствующий заголовок, вы, скорее всего, найдете прототип strerror_r, похороненный в лабиринте #ifdef s. Опция -std изменяет набор предопределенных макросов, влияющих на видимость прототипа.

+0

Но это не объясняет, почему вывод отличается от этого? – Ctx

+0

Да, да. Без прототипа ваша реализация прерывает одну из двух несовместимых версий strerror_r(). Комментарий в string.h объясняет: * Есть 2 варианта «strerror_r», GNU, который возвращает строку и может или не может использовать предоставленный временный буфер и POSIX один , который заполняет строку в буфере. Для того, чтобы использовать версию POSIX, '-D_XOPEN_SOURCE = 600' или' -D_POSIX_C_SOURCE = 200112L' без '-D_GNU_SOURCE' требуется, в противном случае версия ГНУ является предпочтительным. * – Jens

+0

Итак, какая версия используется в первом случае (gnu90/gnu99)? Я предполагаю версию GNU. Во втором случае используется версия posix, которая заполняет строку в буфере. Итак, почему он не печатается? – Ctx

1

strerror_r (3) говорит:

XSI-совместимый strerror_r() является предпочтительным для портативных применений. Он возвращает строку ошибки в пользовательском буфере buf длины buflen.

GNU-специфичный strerror_r() возвращает указатель на строку, содержащую сообщение об ошибке. Это может быть либо указатель на строку, которую функция хранит в buf, либо указатель на некоторую (неизменяемую) статическую строку (в этом случае buf не используется). Если функция хранит строку в buf, то сохраняются не более байтовые байты (строка может быть усечена, если buflen слишком мал и errnum неизвестен). Строка всегда включает завершающий нулевой байт.

Таким образом, дело не только в том, является ли объявление видимым или нет (что является довольно большой проблемой само по себе), когда вы получаете предупреждение «Неявное объявление», вы не должны ожидать, что программа будет работать на все.) Это также вопрос о том, какую версию функции вы вызываете. Иногда версия GNU возвращает указатель на константную строку в библиотеке вместо копирования строки в буфер, предоставляемый вызывающим абонентом.

Основная цель strerror_r - «Я хочу строку в этом буфере»; это «Мне нужна строка, которая позже не будет перезаписана библиотекой».

 Смежные вопросы

  • Нет связанных вопросов^_^