我在学习测试中使用read(2)时遇到了一些问题。
代码如下:
#include <stdio.h>
int main() {
size_t length;
read(0, &length, sizeof(length));
printf("input = %u\n", length);
return 0;
}
我想这个代码将从stdio中读取8个字节(即ascii char),并将它们存储在length变量中。然后它将打印到stdout 8字节的相应unsigned int值。
所以,让我的测试如下:从linux终端运行这个程序,然后点击'enter'。我希望length的值只有10(换行符的ascii值)。
但是运行这个测试(很多次):
$ ./test
len = 4195338
但是这个版本的代码就像我期望的那样:
#include <stdio.h>
int main() {
int a = 10;
size_t length;
int b = 123;
ssize_t n = read(0, &length, sizeof(length));
printf("input = %u\n", length);
return 0;
}
$ ./test
input = 10
那么,有什么意义呢? 为什么我添加一些随机和未使用的变量,如果我存储read()的返回值,那么同一输入的输出会有所不同?
N.B。我知道read(2)是一个原始系统调用,不应该从终端读取输入,这只是一个学习问题。
答案 0 :(得分:1)
如果size_t是8个字节,请在printf中尝试%llu
答案 1 :(得分:1)
如果sizeof(size_t) == 8
,代码将读取8个字节 - 真。
通常,这些字节不会全部为ASCII(意味着某些字节将设置为第8位,值范围为0x80..0xFF,而不是ASCII的一部分)。
但是,没有字符转换。如果您的文件包含12345678
,则值为0x3132333435363738(或者可能为0x3837363534333231)。如果您需要转换,请不要使用read(2)
。
printf()
格式应该是%zu
(C99)或%lu
(C89 size_t
相当于64位unsigned long
;它不能是当然是unsigned long long
和C89。
请注意,您的示例输出不是来自示例代码。示例输出显示为len = ...
,但代码会生成input = ...
。因此,您的一个问题可能是您没有测试您认为自己正在测试的内容。
你发表评论:
我知道read(2)是一个原始系统调用,不应该从终端读取输入。
read(2)
系统调用(可能)由getchar()
等函数用于从终端读取。使用它从终端读取是不正确的。从终端读取字符数组以外的东西可能是不正确的。
我只是从终端运行程序,然后从键盘输入。
喔。烦。我从未想过你会这样做。
好吧,你将一个字节的数据读入一个需要8个字节的变量,然后就会变成垃圾。您的变量未能可靠地初始化。
这是一个带样本输出的SSCCE(Short, Self-Contained, Correct Example):
#include <stdio.h>
#include <unistd.h>
int main(void)
{
size_t length = 0xFFFFFFFFFFFFFFFF;
int nbytes = read(0, &length, sizeof(length));
printf("nbytes = %d: input = %zu (0x%zX)\n", nbytes, length, length);
return 0;
}
两个样本运行:
$ ./test
nbytes = 1: input = 18446744073709551370 (0xFFFFFFFFFFFFFF0A)
$ ./test
12345678
nbytes = 8: input = 4050765991979987505 (0x3837363534333231)
$ ./test < /dev/null
nbytes = 0: input = 18446744073709551615 (0xFFFFFFFFFFFFFFFF)
$
你看到那里发生了什么吗?请注意,SSCCE代码会关注并报告读取的字节数。始终检查类似读取操作的返回值非常重要(这里,具体来说,这意味着read()
);如果您没有获得预期的数据,您的结果可能不是您所期望的。使用“命中换行”之后的值可能是“未定义的行为”,尽管显示的行为是您通常得到的行为。
(在Mac OS X 10.8.3上使用GCC 4.7.1进行测试 - 英特尔芯片,小端。)