为什么在 glibc 中使用 crypt 会导致编译器警告?
Why using crypt in glibc cause compiler warning?
我尝试编译以下代码(最小示例,查看整个代码的编辑):
// a.c
#include <stdio.h>
#define _XOPEN_SOURCE
#include <unistd.h>
int main(int argc, char* argv[])
{
puts((const char*) crypt("AAAA", "22"));
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", "22"));
^
minimum.c:8:10: warning: cast to 'const char *' from smaller integer type 'int' [-Wint-to-pointer-cast]
puts((const char*) crypt("AAAA", "22"));
^
2 warnings generated.
但是 ./a.out
确实有效:
22GKY4KPtBqD9jAhwxIZGDqEShaBaw.pkyJxjvSlKmtygDXKQ2Q62CPY98MPIZbz2h6iMCgLTVEYplzp.naYLz1
我发现如果我像这样删除 #include <stdio.h>
和 puts
:
// new_a.c
#define _XOPEN_SOURCE
#include <unistd.h>
int main(int argc, char* argv[])
{
crypt("AAAA", "22");
return 0;
}
那就没有警告了。
如何在不删除 #include <stdio.h>
的情况下修复这些警告?
编辑:
整个节目:
#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[=14=]
* 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
放在第一行,但警告并没有消失。
宏 _XOPEN_SOURCE
记录在 feature_test_macros(7)
中。特别是,联机帮助页指出:
NOTE: In order to be effective, a feature test macro must be defined before including any header files. This can be done either in the compilation command (cc -DMACRO=value
) or by defining the macro within the source code before including any headers.
当您包含 stdio.h
时,您间接包含了 features.h
,它使用 当时 定义的功能测试宏。特别是,由于 _XOPEN_SOURCE
和 friends 未在此时定义,因此 crypt.h
未声明 [=18=].
当你定义 _XOPEN_SOURCE
时已经太晚了,因为 features.h
有一个包含保护来防止它被包含两次。
通过交换前两行的顺序,代码可以正常工作而不会在我的系统上引发此警告:
#define _XOPEN_SOURCE
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
puts((const char*) crypt("AAAA", "22"));
return 0;
}
由于第二个原因,您的较大示例不起作用:您将 _X_OPEN_SOURCE
写为宏的名称,而正确的名称是 _XOPEN_SOURCE
.
我尝试编译以下代码(最小示例,查看整个代码的编辑):
// a.c
#include <stdio.h>
#define _XOPEN_SOURCE
#include <unistd.h>
int main(int argc, char* argv[])
{
puts((const char*) crypt("AAAA", "22"));
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", "22"));
^
minimum.c:8:10: warning: cast to 'const char *' from smaller integer type 'int' [-Wint-to-pointer-cast]
puts((const char*) crypt("AAAA", "22"));
^
2 warnings generated.
但是 ./a.out
确实有效:
22GKY4KPtBqD9jAhwxIZGDqEShaBaw.pkyJxjvSlKmtygDXKQ2Q62CPY98MPIZbz2h6iMCgLTVEYplzp.naYLz1
我发现如果我像这样删除 #include <stdio.h>
和 puts
:
// new_a.c
#define _XOPEN_SOURCE
#include <unistd.h>
int main(int argc, char* argv[])
{
crypt("AAAA", "22");
return 0;
}
那就没有警告了。
如何在不删除 #include <stdio.h>
的情况下修复这些警告?
编辑:
整个节目:
#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[=14=]
* 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
放在第一行,但警告并没有消失。
宏 _XOPEN_SOURCE
记录在 feature_test_macros(7)
中。特别是,联机帮助页指出:
NOTE: In order to be effective, a feature test macro must be defined before including any header files. This can be done either in the compilation command (
cc -DMACRO=value
) or by defining the macro within the source code before including any headers.
当您包含 stdio.h
时,您间接包含了 features.h
,它使用 当时 定义的功能测试宏。特别是,由于 _XOPEN_SOURCE
和 friends 未在此时定义,因此 crypt.h
未声明 [=18=].
当你定义 _XOPEN_SOURCE
时已经太晚了,因为 features.h
有一个包含保护来防止它被包含两次。
通过交换前两行的顺序,代码可以正常工作而不会在我的系统上引发此警告:
#define _XOPEN_SOURCE
#include <stdio.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
puts((const char*) crypt("AAAA", "22"));
return 0;
}
由于第二个原因,您的较大示例不起作用:您将 _X_OPEN_SOURCE
写为宏的名称,而正确的名称是 _XOPEN_SOURCE
.