系统调用读取结果在结果后显示随机字符
System call read result display random characters after the result
我收到了这个作业,我必须从 file.txt(最大大小 4096B)中读取四次,基本上将它分成 4 个大小相等的字符串。我必须填写这个结构(只考虑字段'msg',我认为问题就在那里):
struct message {
long mtype
int nclient;
int pid;
char path[151];
char msg[1025];
};
我使用了 4 个数组 struct message
来存储所有 4 个部分
这是我的读物:
struct message msgs[4];
for (int i = 0; i < 4; i++) {
msgs[i].nclient=pos+1;
msgs[i].mtype = 42;
msgs[i].pid = getpid();
strcpy(msgs[i].path, filespath[pos]);
if (read(fd, msgs[i].msg, nMsgSize[i]) == -1)
ErrExit("read failed");
printf("I've read: %s\nMSGSize: %d\nPath: %s\n",msgs[i].msg, nMsgSize[i], msgs[i].path);
}
我在文件“sendme_5.txt”上测试了它,其中包含以下文本:
ABCD
这是我的输出:
I've read: A MSGSize: 1 Path:
/home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
I've read: BP"�> MSGSize: 1 Path:
/home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
I've read: C#��;�U MSGSize: 1 Path:
/home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
I've read: D�.�>� MSGSize: 1 Path:
/home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
如果我尝试读取完整文件而不将其分成 4 份(只读取一次),它会正确显示。
当我更改字段时问题开始了 char path[151]
。在更改分配后,我们必须将最大大小从 PATH_MAX(4096) 设置为 151,但我不知道它是否相关。
这里有什么问题?
如上所述,read
does not know what a null-terminated string 是。它处理原始字节,不对其读取的数据做任何假设。
原样,您的字符串可能不是 null-terminated。 printf("%s", msgs[i].msg)
可能会继续读取数据的末尾,可能会超过缓冲区的末尾,搜索 null-terminating 字节。除非读取的数据恰好包含一个 null-terminating 字节,或者缓冲区事先是 zeroed-out(并且没有被 read
完全填充),否则这是 Undefined Behaviour.
成功时,read
returns the number of bytes read into the buffer. This may be less than requested. The return value is of type ssize_t
。
使用此系统调用填充字符串缓冲区时,return 值可用于索引和放置 null-terminating 字节。应始终为这种情况保留一个额外的字节(即,始终最多读取缓冲区大小减一:char buf[256]; read(fd, buf, 255)
)。
始终检查错误,否则 -1
的 return 值将索引缓冲区 out-of-bounds。
假设 nMsgSize[i]
是 msgs[i].msg
缓冲区的确切大小:
ssize_t n;
if (-1 == (n = read(fd, msgs[i].msg, nMsgSize[i] - 1)))
ErrExit("read failed");
msgs[i].msg[n] = 0;
printf("READ:%zd/%d expected bytes, MSG:<<%s>>\n", n, nMsgSize[i] - 1, msgs[i].msg);
我收到了这个作业,我必须从 file.txt(最大大小 4096B)中读取四次,基本上将它分成 4 个大小相等的字符串。我必须填写这个结构(只考虑字段'msg',我认为问题就在那里):
struct message {
long mtype
int nclient;
int pid;
char path[151];
char msg[1025];
};
我使用了 4 个数组 struct message
来存储所有 4 个部分
这是我的读物:
struct message msgs[4];
for (int i = 0; i < 4; i++) {
msgs[i].nclient=pos+1;
msgs[i].mtype = 42;
msgs[i].pid = getpid();
strcpy(msgs[i].path, filespath[pos]);
if (read(fd, msgs[i].msg, nMsgSize[i]) == -1)
ErrExit("read failed");
printf("I've read: %s\nMSGSize: %d\nPath: %s\n",msgs[i].msg, nMsgSize[i], msgs[i].path);
}
我在文件“sendme_5.txt”上测试了它,其中包含以下文本:
ABCD
这是我的输出:
I've read: A MSGSize: 1 Path: /home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
I've read: BP"�> MSGSize: 1 Path: /home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
I've read: C#��;�U MSGSize: 1 Path: /home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
I've read: D�.�>� MSGSize: 1 Path: /home/luca/Desktop/system_call_meh/myDir/joe_bastianich/bruno_barbieri/sendme_5.txt
如果我尝试读取完整文件而不将其分成 4 份(只读取一次),它会正确显示。
当我更改字段时问题开始了 char path[151]
。在更改分配后,我们必须将最大大小从 PATH_MAX(4096) 设置为 151,但我不知道它是否相关。
这里有什么问题?
如上所述,read
does not know what a null-terminated string 是。它处理原始字节,不对其读取的数据做任何假设。
原样,您的字符串可能不是 null-terminated。 printf("%s", msgs[i].msg)
可能会继续读取数据的末尾,可能会超过缓冲区的末尾,搜索 null-terminating 字节。除非读取的数据恰好包含一个 null-terminating 字节,或者缓冲区事先是 zeroed-out(并且没有被 read
完全填充),否则这是 Undefined Behaviour.
成功时,read
returns the number of bytes read into the buffer. This may be less than requested. The return value is of type ssize_t
。
使用此系统调用填充字符串缓冲区时,return 值可用于索引和放置 null-terminating 字节。应始终为这种情况保留一个额外的字节(即,始终最多读取缓冲区大小减一:char buf[256]; read(fd, buf, 255)
)。
始终检查错误,否则 -1
的 return 值将索引缓冲区 out-of-bounds。
假设 nMsgSize[i]
是 msgs[i].msg
缓冲区的确切大小:
ssize_t n;
if (-1 == (n = read(fd, msgs[i].msg, nMsgSize[i] - 1)))
ErrExit("read failed");
msgs[i].msg[n] = 0;
printf("READ:%zd/%d expected bytes, MSG:<<%s>>\n", n, nMsgSize[i] - 1, msgs[i].msg);