我正在按照该教程进行操作,我使用cygwin编译器运行WindowsXP 32位,该教程要求我运行此代码:
#include <stdio.h>
#include <ctype.h>
// forward declarations
int can_print_it(char ch);
void print_letters(char arg[]);
void print_arguments(int argc, char *argv[])
{
int i = 0;
for(i = 0; i < argc; i++) {
print_letters(argv[i]);
}
}
void print_letters(char arg[])
{
int i = 0;
for(i = 0; arg[i] != '\0'; i++) {
char ch = arg[i];
if(can_print_it(ch)) {
printf("'%c' == %d ", ch, ch);
}
}
printf("\n");
}
int can_print_it(char ch)
{
return isalpha(ch) || isblank(ch);
}
int main(int argc, char *argv[])
{
print_arguments(argc, argv);
return 0;
}
但我一直在遇到这个警告:
$ make ex14
cc -Wall -g ex14.c -o ex14
ex14.c: In function ?can_print_it?:
ex14.c:34:5: warning: array subscript has type ?char? [-Wchar-subscripts]
return isalpha(ch) || isblank(ch);
^
ex14.c:34:5: warning: array subscript has type ?char? [-Wchar-subscripts]
我试过四处搜索,虽然我发现很多线程都在谈论类似的错误,他们的答案/解决方案都没有在我的代码上工作,但我找不到与学习C相关的问题艰难的方式 exercise 14。
那么我应该怎样做才能摆脱这种警告?
答案 0 :(得分:4)
警告的原因是char值通常是正值,但有时它们可能是负值;对于程序员来说这可能是意料之外的(特别是因为在某些实现中char总是正数),并且对数组使用负索引显然是一件坏事。
isalpha完全支持你的背后。您可以通过将char转换为int或通过将其存储在int中来修复警告 - 但这并不能解决问题,因为负char将被强制转换为具有完全相同问题的负int。您可以通过将char转换为unsigned char来修复警告和问题。
答案 1 :(得分:3)
所以,如果我们看一下gcc document for warnings which covers -Wchar-subscripts,那就说:
如果数组下标的类型为char,则发出警告。这是导致错误的常见原因,因为程序员经常忘记这种类型是在某些机器上签名的。 -Wall启用此警告。
实现定义 char 是签名还是未签名,如果使用 unsigned char ,则警告将消失。
我们可以从草案C99标准中看到,<ctype.h>
中函数的参数可以表示为 unsigned char 或EOF
,来自{{1}部分} 字符处理&lt; ctype.h&gt; :
在所有情况下,参数都是一个int,其值应为 可表示为无符号字符或等于宏EOF的值。如果 参数有任何其他值,行为未定义
所以最有可能将7.4
和isalpha
实现为使用查找表的宏,因此这段代码确实会使用char来索引数组。
答案 2 :(得分:0)
isalpha
和isblank
的输入类型应为int
,而不是char
。这是核心问题。其余的是如何实施的细节。如果使用-E
标志来预处理代码,则函数can_print_it
会扩展为:
int can_print_it(char ch)
{
return (((__ctype_ptr__+sizeof(""[ch]))[(int)(ch)])&(01|02)) || __extension__ ({ __typeof__ (ch) __x = (ch); (((__ctype_ptr__+sizeof(""[__x]))[(int)(__x)])&0200) || (int) (__x) == '\t';});
}
如您所见,输入ch
在isalpha
的实现中用作数组索引。临时__x
与ch
的类型相同,在isblank
的实现中用作数组索引。
您可以通过以下方式修正警告:
将can_print_it
的参数类型更改为int
。
int can_print_it(int ch)
{
return isalpha(ch) || isblank(ch);
}
在函数中创建临时变量并使用它来调用isalpha
和isblank
。
int can_print_it(char ch)
{
int temp = ch;
return isalpha(temp) || isblank(temp);
}
答案 3 :(得分:0)
您的编译器似乎已旧或已损坏。 GCC 4.9.1编译此代码时没有警告/错误,给出:
gcc test.c -std=c11 -pedantic-errors -Wall -Wextra
编译器必须隐式地将您的char提升为isalpha等函数所需的int。无论char的实现定义签名如何,它都会进行此促销。 char的大小也无关紧要,因为char总是一个小整数类型。
我期望编译器从这段代码中给出的唯一警告类似于“从char到int的隐式转换”。