初始化静态初始化的每结构字符缓冲区的最佳方法?

发布于 2024-10-16 12:11:17 字数 1560 浏览 8 评论 0原文

继续绝对最快(和希望优雅)的方式返回给定结构类型的某个字符缓冲区 我现在想分别初始化每个结构的每个静态字符 buf 一次。

即,对于:

#pragma pack(push, 1);

struct Header {
   int a;
   int b;
   char c;
};

struct X {
   int x;
   int y;
};

struct Y {
   char someStr[20];
};

struct Msg {
   Header hdr;
   union {
      X x;
      Y y;
   };
};

#pragma pack(pop)

我们有:

tempate<typename T>
struct Buffer {
    static char buffer[sizeof(T)];
}

template<class T>
inline char* get_buffer() {
  return Buffer<T>::buffer;
}

我正在寻找的两件事是:

  1. 正好有 2 个缓冲区: 1 个用于 X,一个用于 Y。它们的长度应分别为 sizeof(Msg.hdr) + sizeof(Msg.x ) 和 sizeof(Msg.hdr) + sizeof(Msg.y) 分别。
  2. 每个缓冲区在应用程序生命周期内都会被多次检索,并且只有某些字段真正(或需要)更改。 2a.由其字符缓冲区支持的 X 的消息应初始化为 m.hdr.a = 1、m.hdr.b = 0;对于 Msg Y,它应该是 m.hdr.a = 16; m.hdr.b = 1;举个例子。
  3. 应用程序将经常以 X 或 Y 支持的类型 Msg 的形式获取这些缓冲区(应用程序会知道是哪一个),然后仅更改 x 和 y 或 someStr,然后将其输出到文件,例如然后重复。

只是想知道在 @6502 和 @Fred Nurk 的这些出色示例的基础上构建了什么好方法来优雅地初始化这两个缓冲区,同时又易于人类阅读。我更愿意继续使用结构体并尽可能限制reinterpret_cast<>() 的使用,因为可能会出现别名问题。

如果我不清楚,请告诉我,我将尽力回答任何问题和/或编辑此问题描述。

谢谢。

*** 更新:我对这些缓冲区的使用模式是,我将发送将 char* 复制到流或文件中。因此我需要获取一个指向底层数据的 char* 指针。然而,为了可读性和方便性,我需要通过它们的结构来处理字符缓冲区。此外,这个字符缓冲区应该是解耦的,不一定包含或“附加”到结构中,因为结构几乎位于单独的文件中,并在不需要/不需要缓冲区的其他地方使用。只是做一个简单的静态 X x;静态 Y y;对于 X 的消息缓冲区来说,长度 Header + X 的缓冲区是否足够或可能更好?然后以某种方式保留对 X 和 Y 的每个消息的 char* 引用?我会遇到潜在的别名问题吗?

Continuing from Absolute fastest (and hopefully elegant) way to return a certain char buffer given a struct type I want to now initialize once each static character buf per struct individually.

Ie, for:

#pragma pack(push, 1);

struct Header {
   int a;
   int b;
   char c;
};

struct X {
   int x;
   int y;
};

struct Y {
   char someStr[20];
};

struct Msg {
   Header hdr;
   union {
      X x;
      Y y;
   };
};

#pragma pack(pop)

We have:

tempate<typename T>
struct Buffer {
    static char buffer[sizeof(T)];
}

template<class T>
inline char* get_buffer() {
  return Buffer<T>::buffer;
}

The two things I'm looking for are:

  1. There are exactly 2 buffers: 1 for X and one for Y. They should each be the length of sizeof(Msg.hdr) + sizeof(Msg.x) and sizeof(Msg.hdr) + sizeof(Msg.y), respectively.
  2. Each buffer will be retrieved a lot during the application lifetime and only some fields really (or need to) change.
    2a. Msg for X backed by it's char buffer should be initialized to m.hdr.a = 1, m.hdr.b = 0; and for Msg Y it should be m.hdr.a = 16; m.hdr.b = 1; as an example.
  3. The app will frequently fetch these buffers as type Msg backed by either X or Y (the app would know which one) and then change x and y or someStr only and then output it to the file for example then repeat.

Just wondering what nice way builds on these great examples by @6502 and @Fred Nurk to elegantly initialize these 2 buffers while being human readable. I'd prefer to keep using structs and to limit the use of reinterpret_cast<>() as much as possible as there may be aliasing issues that might develop.

Please let me know if I'm not clear and I will do my best to answer any questions and/or edit this question description.

Thanks.

*** Update: my usage pattern of these buffers is that I will be sending copying the char* out to a stream or file. hence I need to get a char* pointer to the underlying data. However I need to work on the char buffers via their structs for readability and convenience. Also this char buffer should be decoupled and not necessarily contained or "attached" to the struct as the structs are pretty much in separate files and used elsewhere where the buffers are not needed/wanted. Would just doing a simple static X x; static Y y; suffice or Maybe better buffers of length Header + X for X's Msg buffer? and then somehow just keep a char* reference to each Msg for X and Y? Will I run into aliasing issues potentially?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

一向肩并 2024-10-23 12:11:17

如果您用 C 语言编写它,您可以研究一个相当常见的 C 编译器扩展,称为“强制转换为联合类型”,但在 C++ 中它不再存在。

在C++中,没有办法绕过reinterpret_cast<>满足您的要求,但至少您可以通过计算转换为联合的 NULL 指针上的成员偏移量来相当安全地完成此操作,然后在将其转换为联合之前从数据指针中减去该偏移量。我相信在大多数编译器上偏移量将为 0,但为了安全起见更好。

template<class T>
union Aligner {
    T t;
    char buffer[sizeof(T)];
};

template<class T>
inline char* get_buffer(T* pt) {

    return reinterpret_cast<Aligner<T>*>(reinterpret_cast<char*>(pt) - reinterpret_cast<ptrdiff_t>(&reinterpret_cast<Aligner<T>*>(NULL)->t))->buffer;
}

If you would be writing it in C, you could look into a fairly common C compiler extension called "cast to a union type", but in C++ it is no longer present.

In C++ there is no way around reinterpret_cast<> for what you require, but at least you can do it fairly safely by calculating the member offset on NULL pointer casted to the union, and then subtracting this offset from your data pointer before casting it to the union. I believe that on most compilers the offset will be 0, but it is better to be on the safe side.

template<class T>
union Aligner {
    T t;
    char buffer[sizeof(T)];
};

template<class T>
inline char* get_buffer(T* pt) {

    return reinterpret_cast<Aligner<T>*>(reinterpret_cast<char*>(pt) - reinterpret_cast<ptrdiff_t>(&reinterpret_cast<Aligner<T>*>(NULL)->t))->buffer;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文