系统调用读取结果在结果后显示随机字符

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);