在数组之后直接放置char的可靠方法

时间:2017-06-01 14:12:30

标签: c++ c++11

我使用以下代码从套接字中读取:

char buf[4097];
int ret = read(fd, buf, sizeof(buf) - 1);
buf[ret] = 0x0;
std::cout << buf << "\n";

但是,我不喜欢那里4097sizeof(buf) - 1的需要。这种东西很容易忘记。所以我想知道,是否有一些很好的方法可以在数组之后直接在堆栈上强制编译器而不是0x0

我喜欢的是

char buf[4096];
char _ = 0x0;
int ret = read(fd, buf, sizeof(buf));
buf[ret] = 0x0;
std::cout << buf << "\n";

但我不知道如何强制编译器之间没有任何东西(afaik #pragma pack仅适用于结构,而不适用于堆栈)。

4 个答案:

答案 0 :(得分:3)

我会保持简单:

ssize_t read_and_put_0(int fd, void *buf, size_t count)
{
    ssize_t ret = read(fd, buf, count - 1);
    if (ret != -1) // Or `if (ret <= 0)`
        ((char *)buf)[ret] = 0x0;
    return ret;
}

// ...

char buf[4097];
read_and_put_0(fd, buf, sizeof buf);

答案 1 :(得分:2)

  

我不喜欢那里4097sizeof(buf) - 1

的需要

简洁美观:

constexpr std::size_t size = 4096;
char buf[size + 1];
int ret = read(fd, buf, size);
buf[ret] = 0x0;

您可以指定所需的大小,无需手动添加。并且既不需要sizeof,也不需要减去1。

在我看来,记住+ 1表示终结符比记住声明一个单独的字符对象更容易 - 不管怎么说它都不能直接在数组之后。

也就是说,与read相比,阅读文本文件的方法更容易出错。

答案 2 :(得分:1)

未指定的不同变量值的内存相对位置。实际上,一些变量可能根本不存在于内存中。如果要确保内存中数据的相对布局,请使用结构或类。例如:

struct {
    char buf[4096];
    char term;
} tbuf = { { 0 }, 0 };

int ret = read(fd, tbuf.buf, sizeof(tbuf.buf));
if (ret >= 0 && ret < sizeof(tbuf.buf)) {
    tbuf.buf[ret] = '\0';
}

结构的成员保证按照声明的顺序在内存中布局,因此您可以确信故障安全终止符tbuf.term将遵循tbuf.buf。但是,你不能确信它们之间没有填充。此外,这只是一个故障保险。如图所示,您仍需要编写空终止符,以防短读。

此外,即使tbuf的表示肯定比其buf成员大至少一个字节,它仍然会产生UB以访问其边界之外的tbuf.buf。总的来说,我不认为你获得了很多,如果有的话。

答案 3 :(得分:1)

HolyBlackCats答案的替代方案,只要您拥有数组而不是指向某个数组的指针,就不需要给出size参数。

template <size_t N> ssize_t read_and_put_0(int fd, char (&buf)[N]) {
    ssize_t ret = read(fd, buf, N - 1);
    if(ret != -1) // Or `if (ret <= 0)`
        buf[ret] = 0x0;
    return ret;
}

char buf[4097];
read_and_put_0(fd, buf);