C POSIX读取(2),意外行为
我在学习测试中使用read(2)时遇到一些问题 代码如下:C POSIX读取(2),意外行为,c,posix,undefined-behavior,C,Posix,Undefined Behavior,我在学习测试中使用read(2)时遇到一些问题 代码如下: #include <stdio.h> int main() { size_t length; read(0, &length, sizeof(length)); printf("input = %u\n", length); return 0; } 但是这个版本的代码就像我期望的那样: #include <stdio.h> int main() { int
#include <stdio.h>
int main() {
size_t length;
read(0, &length, sizeof(length));
printf("input = %u\n", length);
return 0;
}
但是这个版本的代码就像我期望的那样:
#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
#包括
int main(){
INTA=10;
尺寸与长度;
int b=123;
ssize_t n=read(0,&length,sizeof(length));
printf(“输入=%u\n”,长度);
返回0;
}
美元/测试
输入=10
那么,重点是什么?
为什么如果我添加一些随机和未使用的变量,并且如果我存储read()的返回值,那么来自相同输入的输出将不同
注意:我知道read(2)是一个原始的系统调用,不应该从终端读取输入,这只是一个学习问题。如果大小t为8字节,请在打印中尝试%llu如果
大小f(大小t)==8
,代码将读取8字节-true
通常,这些字节不都是ASCII(意味着有些字节将设置第8位,并且值的范围为0x80..0xFF,这不是ASCII的一部分)
但是,没有字符转换。如果文件包含12345678
,则该值将为0x31323334353637338(或者可能为0x3837363534333231)。如果需要转换,则不使用read(2)
printf()
格式应该是%zu
(C99)或%lu
(C89的大小等于64位无符号长
;当然,它不能是无符号长
和C89)
请注意,示例输出不是来自示例代码。示例输出显示len=…
,但代码将生成input=…
。所以,你的问题之一可能是你没有测试你认为你正在测试的东西
您的评论:
我知道read(2)是一个原始的系统调用,不应该从终端读取输入
read(2)
系统调用(可能)由getchar()
等函数用于从终端读取。使用它从终端读取数据是正确的。从终端读取字符数组以外的内容可能是不正确的
我只需从终端运行程序,然后从键盘按enter键
哦。麻烦。我从没想过你会那样做
嗯,你把一个字节的数据读入一个需要8个字节的变量,你就会得到垃圾。您的变量未可靠初始化
下面是一个带有示例输出的SSCCE():
#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;
}
#包括
#包括
内部主(空)
{
大小\u t长度=0xFFFFFFFFFFFFFF;
int nbytes=读取(0,&length,sizeof(length));
printf(“n字节=%d:输入=%zu(0x%zX)\n”,n字节,长度,长度);
返回0;
}
两个样本运行:
$ ./test
nbytes = 1: input = 18446744073709551370 (0xFFFFFFFFFFFFFF0A)
$ ./test
12345678
nbytes = 8: input = 4050765991979987505 (0x3837363534333231)
$ ./test < /dev/null
nbytes = 0: input = 18446744073709551615 (0xFFFFFFFFFFFFFFFF)
$
$/测试
n字节=1:输入=18446744073709551370(0xFFFFFFFFFF0A)
美元/测试
12345678
n字节=8:输入=4050765991979987505(0x3837363534333231)
$/测试
你看到那里发生了什么吗?请注意,SSCCE代码关注并报告读取的字节数。务必始终检查类读取操作的返回值(这里,这意味着read()
);如果你没有得到你期望的那么多数据,你的结果可能也不是你期望的。在“hit newline”案例之后使用值可能是“未定义的行为”,尽管所显示的行为通常是您通常会得到的
(在Mac OS X 10.8.3上使用GCC 4.7.1进行测试-英特尔芯片,little endian。)如何将数据送入程序?在程序中输入的是什么-输入数据是什么。(还有一个len=4195338
应该是input=4195338
)@JonathanLeffler我只是从终端运行程序,然后从键盘按回车键。对不起,len=…
只是复制粘贴过程中的一个错误。我编辑。感谢您提供的其他信息。提供SSCCE()有很多好处,因为这样我们可以看到您真正在做什么。它只会在代码中添加6-10行(最多)。它还可能解答程序输入是什么的谜团-您还没有展示它。只有main()相关的LOC。顺便说一句,我会编辑这个问题^^非常感谢你。但是,为什么在第二个版本中我得到10作为输出?长度变量也未初始化。纯粹是意外,length
变量恰好被初始化为0,因此读取换行符('\n'
或10)恰好将最低有效字节设置为10。我在那个字节中得到了0x0A。您也在使用一个小小的endian(英特尔)CPU。由于length
未在代码中显式初始化,因此无法可靠地预测修改其中一个字节时将得到的值,因为其他七个字节没有确定的值。
$ ./test
nbytes = 1: input = 18446744073709551370 (0xFFFFFFFFFFFFFF0A)
$ ./test
12345678
nbytes = 8: input = 4050765991979987505 (0x3837363534333231)
$ ./test < /dev/null
nbytes = 0: input = 18446744073709551615 (0xFFFFFFFFFFFFFFFF)
$