std::string 不适合作为read 的第二个参数。您需要传递 read 一个缓冲区,将其数据连同要从管道读取的字节数一起写入该缓冲区。
如果您先将字符串的长度写入管道,您的生活会变得更加简单。这样你就可以知道要从管道中读取多少字节:
int main() {
int fd[2];
pipe(fd);
pid_t pid = fork();
if (pid == 0) {
close(fd[0]);
std::string str = "some data";
std::string::size_type size = str.size();
write(fd[1], &size, sizeof(size));
write(fd[1], str.c_str(), str.size());
} else {
close(fd[1]);
std::string::size_type size;
read(fd[0], &size, sizeof(size));
std::string str(size, ' ');
// This depends on the fact that the pointer returned by data
// is non-const in C++17.
// Use &str[0] instead of str.data() if using an older C++ standard
read(fd[0], str.data(), size);
}
}
在此示例中,子进程首先将字符串的长度写入管道,然后将字符串数据本身写入(值得注意的是,它不会将 nul 终止符写入管道)。然后父级读取长度,分配适当大小的字符串,并将数据读入由该字符串管理的缓冲区。
如果您不想先写入字符串的长度,则必须一次读取一个块,直到找到一个以 nul 字节结尾的块:
int main() {
int fd[2];
pipe(fd);
pid_t pid = fork();
if (pid == 0) {
close(fd[0]);
std::string str = "some data";
write(fd[1], str.c_str(), str.size() + 1);
} else {
close(fd[1]);
std::string str;
while (true) {
char c[100];
ssize_t count = read(fd[0], c, 100);
if (c[count - 1] == '\0') {
// Don't copy an extra nul terminator into the string object
str.append(c, c + count - 1);
break;
} else {
str.append(c, c + count);
}
}
}
}
在此示例中,子进程将字符串数据写入带有 nul 终止符的管道。然后父进程从管道中读取 100 字节的块,将数据附加到字符串中,直到它读取一个以 nul 字节结尾的块。