putchar() 奇怪的输出,为什么会这样?
putchar() weird output, why is this happening?
如果我将单词 "Hello World" 键入标准输入流,此程序将打印出奇怪的框符号而不是预期的 "Hello World" 回到标准输出。
#include <stdio.h>
int main(void)
{
// print out all characters from the stream until '/n' character is found
int ch;
while (ch = getchar() != '\n')
{
putchar(ch);
}
putchar('\n');
}
我知道如何解决这个问题。但是为什么这行代码不正确呢?
while (ch = getchar() != '\n')
您需要注意 operator precedence - !=
等比较运算符的优先级高于赋值运算符 (=
)。使用括号强制执行所需的行为,即更改:
while (ch = getchar() != '\n')
至:
while ((ch = getchar()) != '\n')
附录:请务必注意@TomGoodfellow 在下面单独回答中的建议 - 使用启用警告的体面编译器(例如 gcc -Wall
)会立即提醒您注意此问题。
(ch = getchar() != '\n')
应该改写为
((ch = getchar()) != '\n')
因为 !=
比 C operator precedence table 中的 =
绑定得更紧。运算符并不像人们预期的那样从左到右(英语阅读方向)排序。例如 2 + 3 * 5
的结果是 17
而 不是 25
。这是因为 *
会在执行 +
之前执行,因为 *
运算符比 +
运算符具有更高的优先级。
所以当你写类似
的东西时
ch = getchar() != '\n'
您希望它等同于:(ch = getchar()) != '\n'
但实际上相当于:ch = (getchar() != '\n')
因为 !=
的结果是 true
或 false
,您会在屏幕上看到字符 [=27=]1
。我相信 [=27=]1
在您的系统上显示为方框 1。
1: 字符 [=27=]1
可能显示为方框、点或一些奇怪的字符,也可能根本不出现在输出中。
因为需要写成while ((ch = getchar()) != '\n')
作为一个略微元化的答案,总体修复总是在启用警告的情况下进行编译:
$ gcc t.c -Wall
t.c: In function ‘main’:
t.c:7:5: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
while (ch = getchar() != '\n')
^
t.c:12:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
或者更好地尝试 clang,默认情况下会发出警告并且通常会提供更好的诊断消息:
$ clang t.c
t.c:7:15: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
while (ch = getchar() != '\n')
~~~^~~~~~~~~~~~~~~~~~~
t.c:7:15: note: place parentheses around the assignment to silence this warning
while (ch = getchar() != '\n')
^
( )
t.c:7:15: note: use '==' to turn this assignment into an equality comparison
while (ch = getchar() != '\n')
^
==
1 warning generated.
如果我将单词 "Hello World" 键入标准输入流,此程序将打印出奇怪的框符号而不是预期的 "Hello World" 回到标准输出。
#include <stdio.h>
int main(void)
{
// print out all characters from the stream until '/n' character is found
int ch;
while (ch = getchar() != '\n')
{
putchar(ch);
}
putchar('\n');
}
我知道如何解决这个问题。但是为什么这行代码不正确呢?
while (ch = getchar() != '\n')
您需要注意 operator precedence - !=
等比较运算符的优先级高于赋值运算符 (=
)。使用括号强制执行所需的行为,即更改:
while (ch = getchar() != '\n')
至:
while ((ch = getchar()) != '\n')
附录:请务必注意@TomGoodfellow 在下面单独回答中的建议 - 使用启用警告的体面编译器(例如
gcc -Wall
)会立即提醒您注意此问题。
(ch = getchar() != '\n')
应该改写为
((ch = getchar()) != '\n')
因为 !=
比 C operator precedence table 中的 =
绑定得更紧。运算符并不像人们预期的那样从左到右(英语阅读方向)排序。例如 2 + 3 * 5
的结果是 17
而 不是 25
。这是因为 *
会在执行 +
之前执行,因为 *
运算符比 +
运算符具有更高的优先级。
所以当你写类似
的东西时ch = getchar() != '\n'
您希望它等同于:(ch = getchar()) != '\n'
但实际上相当于:ch = (getchar() != '\n')
因为 !=
的结果是 true
或 false
,您会在屏幕上看到字符 [=27=]1
。我相信 [=27=]1
在您的系统上显示为方框 1。
1: 字符 [=27=]1
可能显示为方框、点或一些奇怪的字符,也可能根本不出现在输出中。
因为需要写成while ((ch = getchar()) != '\n')
作为一个略微元化的答案,总体修复总是在启用警告的情况下进行编译:
$ gcc t.c -Wall
t.c: In function ‘main’:
t.c:7:5: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
while (ch = getchar() != '\n')
^
t.c:12:1: warning: control reaches end of non-void function [-Wreturn-type]
}
^
或者更好地尝试 clang,默认情况下会发出警告并且通常会提供更好的诊断消息:
$ clang t.c
t.c:7:15: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
while (ch = getchar() != '\n')
~~~^~~~~~~~~~~~~~~~~~~
t.c:7:15: note: place parentheses around the assignment to silence this warning
while (ch = getchar() != '\n')
^
( )
t.c:7:15: note: use '==' to turn this assignment into an equality comparison
while (ch = getchar() != '\n')
^
==
1 warning generated.