В чем разница между crypt в unistd.h и crypt.h? - PullRequest
0 голосов
/ 01 февраля 2019

Фон

crypt имеет два определения, из документов,

  1. В одном из них используется unistd.h

    #define _XOPEN_SOURCE       /* See feature_test_macros(7) */
    #include <unistd.h>
    

    Это определяется как

    #ifdef __USE_MISC
    
    extern char *crypt (const char *__key, const char *__salt)
         __THROW __nonnull ((1, 2));
    #endif
    
  2. Один из них использует GNU crypt.h

    #define _GNU_SOURCE         /* See feature_test_macros(7) */
    #include <crypt.h>
    

    Это определяется как

    extern char *crypt (const char *__phrase, const char *__salt)                                                                                          
      __THROW __nonnull ((1, 2));
    

Проблема

Когда я компилирую с определением в первом примере (unistd.h)

#define _XOPEN_SOURCE
#include <unistd.h>                                                                                                                                  
#include <stdio.h>                                                                                                                                   

int main()                                                                                                                                           
{                                                                                                                                                    
  printf("%s", crypt("foobar", "sa"));                                                                                                               
}

Я получаю ошибку

In function ‘main’:
warning: implicit declaration of function ‘crypt’; did you mean ‘chroot’? [-Wimplicit-function-declaration]
  printf("%s", crypt("foobar", "sa"));
               ^~~~~
               chroot
warning: format ‘%s’ expects argument of type ‘char *’, but argument 2 has type ‘int’ [-Wformat=]
  printf("%s", crypt("foobar", "sa"));
          ~^   ~~~~~~~~~~~~~~~~~~~~~
          %d

В отчаянии я попытался добавить это.

#define _XOPEN_VERSION 700
#define _POSIX_VERSION 200809L
#define __USE_MISC 1

В Ubuntu Trusty 14.04 я считаю, что это работает нормально, используя декларацию unistd.h, что еще больше сбивает с толку.

Ответы [ 2 ]

0 голосов
/ 01 февраля 2019

Вы должны игнорировать unistd.h.Это объявление существует для совместимости с POSIX, но GLIB удалил определение для crypt, когда они перешли на libxcrypt, чтобы разработать эти функции в изоляции от glibc.Это означает, что вы все еще можете получить ABI-совместимость, но должны указывать ссылку в crypt.Вы можете узнать больше об этом здесь

Доступность в glibc

Функции crypt (), encrypt () и setkey () являются частью POSIX.1-2008 XSI Options Group для шифрования и не являются обязательными.Если интерфейсы недоступны, то символическая константа _XOPEN_CRYPT либо не определена, либо определена в -1 и может быть проверена во время выполнения с помощью sysconf ().

Это может иметь место, если нисходящий дистрибутив имеетпереключился с крипты glibc на libxcrypt.При перекомпиляции приложений в таких дистрибутивах пользователь должен определить, недоступен ли _XOPEN_CRPYT, и включить crypt.h для прототипов функций;в противном случае libxcrypt является заменой, совместимой с ABI.

Что касается того, почему, даже если вы связываете определение, оно не сбрасывается с

#define _XOPEN_VERSION 700
#define _POSIX_VERSION 200809L
#define __USE_MISC 1
#define _XOPEN_SOURCE

Ну, естьнесколько вещей, которые там происходят

  1. Единственный заголовок, который имеет значение в unistd.h, это __USE_MISC.
  2. unistd.h включает features.h, что undef s__USE_ макросы для запуска с «чистого листа»
  3. Единственный способ определить __USE_MISC - это определить _GNU_SOURCE.

Если вы хотитеизвлеките объявление crypt.h из unistd.h, которое вы должны определить _GNU_SOURCE! Эти два примера, приведенные с справочной страницы crypt.h, делают то же самое, и независимо от того, включаете ли вы unistd.h или crypt.h, вы ДОЛЖНЫ также определять _GNU_SOURCE в современных версиях glibc.

Таким образом, вы можете либо сделать,

#define _GNU_SOURCE
#include <unistd.h>

Или

#define _GNU_SOURCE
#include <crypt.h>

Но поскольку вы должны ссылаться на crypt (-lcrypt), я бы предложилиспользуя объявление в crypt.h для здравомыслия.

0 голосов
/ 01 февраля 2019

Это две декларации , а не два определения .Содержимое файла заголовка не влияет на то, какое определение функции включено: это определяется компоновщиком.В стандартной библиотеке Unix C есть только одно определение функции crypt, на что указывает символ crypt в libcrypt.a или libcrypt.so (в зависимости от того, статически или динамически вы ссылаетесь).

Поскольку эти два объявления совместимы, не имеет значения, через какой заголовок программа проходит.Также хорошо, если оба объявления обрабатываются: программа может содержать любое количество объявлений для функции, если они совместимы.Не вдаваясь в подробности (см. Спецификацию языка C), два объявления функций совместимы, если имеют одинаковый тип возвращаемого значения, одинаковое количество аргументов и одинаковый тип для каждого аргумента.Имя аргумента, приведенное в объявлении, не имеет значения.

...