C++ 在数组后直接放置字符的可靠方法

C++ 在数组后直接放置字符的可靠方法,c++,c++11,C++,C++11,我使用以下代码从套接字读取: char buf[4097]; int ret = read(fd, buf, sizeof(buf) - 1); buf[ret] = 0x0; std::cout << buf << "\n"; 但我不知道如何强制编译器不使用,但介于两者之间的任何东西afaik pragma pack只能在结构上工作,而不能在堆栈上工作。我会保持简单: ssize_t read_and_put_0(int fd, void *buf, size_t c

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

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

但我不知道如何强制编译器不使用,但介于两者之间的任何东西afaik pragma pack只能在结构上工作,而不能在堆栈上工作。

我会保持简单:

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

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

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。总的来说,我认为你不会因此得到什么好处

我不喜欢那里需要4097和sizeofbuf-1

简单就是美丽:

constexpr std::size_t size = 4096;
char buf[size + 1];
int ret = read(fd, buf, size);
buf[ret] = 0x0;
您可以精确地指定所需的大小,无需手动添加。不需要sizeof,也不需要减去1

在我看来,记住+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);

喜欢char buf[4097]={0};?这叫做初始化…字符无效。你不能说出这样的字符。如果你在C++中编程,那么请只使用那个标签,即使问题的部分可以与C和C++相关的大部分是两种非常不同的语言,语义也非常不同。@ LeSaleQualter一个下划线是一个合法的符号。两个、三个或更多。唯一的限制是,在所有作用域中,以两个下划线开头的名称都是为编译器和标准库保留的。如果数据是字符串,并且您的代码暗示它是字符串,则使用fgets。但是,是的,动机是不令人信服的。我不明白为什么它不工作,如果uu将在buf之后;如果ret==sizeofbuf,它将用数据填充整个缓冲区,而buf[ret]=0将把uu设置为0x0。所以它应该在不崩溃的情况下工作。。。我想我遗漏了一些东西:/@Paladin u就在buf之后的源代码中。编译器可能无法像您希望的那样在内存中找到这两个变量。@Paladin如果rettemplate <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);