【问题标题】:Why using crypt in glibc cause compiler warning?为什么在 glibc 中使用 crypt 会导致编译器警告?
【发布时间】:2019-01-06 04:13:34
【问题描述】:

我尝试编译以下代码(最小示例,请参阅整个代码的编辑):

// a.c
#include <stdio.h>

#define _XOPEN_SOURCE
#include <unistd.h>

int main(int argc, char* argv[])
{
    puts((const char*) crypt("AAAA", "$6$2222"));
    return 0;
}

使用clang-7 -lcrypt a.c 并发出以下警告:

minimum.c:8:24: warning: implicit declaration of function 'crypt' is invalid in C99 [-Wimplicit-function-declaration]
    puts((const char*) crypt("AAAA", "$6$2222"));
                       ^
minimum.c:8:10: warning: cast to 'const char *' from smaller integer type 'int' [-Wint-to-pointer-cast]
    puts((const char*) crypt("AAAA", "$6$2222"));
         ^
2 warnings generated.

./a.out 似乎确实有效:

$6$2222$6GKY4KPtBqD9jAhwxIZGDqEShaBaw.pkyJxjvSlKmtygDXKQ2Q62CPY98MPIZbz2h6iMCgLTVEYplzp.naYLz1

我发现如果我像这样删除#include &lt;stdio.h&gt;puts

// new_a.c
#define _XOPEN_SOURCE
#include <unistd.h>

int main(int argc, char* argv[])
{
    crypt("AAAA", "$6$2222");
    return 0;
}

那么就没有警告了。

如何在不删除 #include &lt;stdio.h&gt; 的情况下修复这些警告?

编辑:

整个程序:

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

#define _X_OPEN_SOURCE
#include <unistd.h>

#include <assert.h>

void* Calloc(size_t cnt, size_t size)
{
    void *ret = calloc(cnt, size);
    assert(ret);
    return ret;
}

size_t GetSaltLen(const char *salt)
{
    size_t salt_len = strlen(salt);
    assert(salt_len >  0);
    assert(salt_len <= 16);
    return salt_len;
}

char* GetSaltAndVersion(const char version, const char *salt)
{
    size_t saltlen = GetSaltLen(salt);
    /*
     * The format of salt:
     *     $one_digit_number$up_to_16_character\0
     * For more info, check man crypt.
     */
    char *ret = (char*) Calloc(1 + 1 + 1 + saltlen + 1, sizeof(char));

    char *beg = ret;

    *beg++ = '$';
    *beg++ = version;
    *beg++ = '$';
    memcpy((void*) beg, (const void*) salt, saltlen + 1);

    return ret;
}

void crypt_and_print(const char *passwd, const char *salt_and_version)
{
    char *result = crypt(passwd, salt_and_version);
    assert(puts(result) != EOF);
}

int main(int argc, char* argv[])
{
    if (argc != 4) {
        fprintf(stderr, "argc = %d\n", argc);
        return 1;
    }

    char *salt_and_version = GetSaltAndVersion(argv[2][0], argv[3]);
    crypt_and_print(argv[1], salt_and_version);
    free(salt_and_version);

    return 0;
}

我已按照@Andrey Akhmetov 的建议尝试并将#define 放在第一行,但警告并没有消失。

【问题讨论】:

  • 您应该指定一个值 #define _XOPEN_SOURCE 700(对于 POSIX 2008,当前版本)或 600 或 500 对于旧版本。不指定值会导致准不确定的行为;标头可能将其视为 0,并且不清楚哪个版本的 POSIX(X/Open)由版本号 0 标识。
  • #define _X_OPEN_SOURCE 700 并且它不适用于我的原始代码。
  • 你打错了:它是_XOPEN_SOURCE 而不是_X_OPEN_SOURCE

标签: c clang compiler-warnings glibc crypt


【解决方案1】:

_XOPEN_SOURCE 记录在 feature_test_macros(7) 中。特别是,手册页指出:

注意:为了有效,功能测试宏必须在包含任何头文件之前定义。这可以在编译命令 (cc -DMACRO=value) 中完成,也可以通过在包含任何标头之前在源代码中定义宏来完成。

当您包含stdio.h 时,您间接包含features.h,它使用当时定义的功能测试宏。特别是,由于此时尚未定义 _XOPEN_SOURCE 和朋友,因此 crypt.h 不会声明 crypt

当您定义_XOPEN_SOURCE 时为时已晚,因为features.h 有一个包含保护,防止它被包含两次。

通过交换前两行的顺序,代码可以正常工作而不会在我的系统上引发此警告:

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

int main(int argc, char* argv[])
{
    puts((const char*) crypt("AAAA", "$6$2222"));
    return 0;
}

您的较大示例因第二个原因不起作用:您将 _X_OPEN_SOURCE 写为宏的名称,而正确的名称是 _XOPEN_SOURCE

【讨论】:

  • 通过指定 #define _XOPEN_SOURCE 700 来请求更现代的标准也是一个好主意(例如,500、600、700 是合理的值)。
  • 我已经尝试过,这适用于我的最小示例,但不适用于原始代码
  • @JiaHaoXu 请看编辑;你有一个额外的下划线。
猜你喜欢
  • 2016-06-15
  • 1970-01-01
  • 1970-01-01
  • 2017-11-03
  • 1970-01-01
  • 2013-04-03
  • 1970-01-01
  • 2017-07-12
  • 2018-03-31
相关资源
最近更新 更多