具有 N 个字段的类型 A 是否可以将其合并到具有 N+x 个字段的类型 B 的新对象中?

Having type A with N fields is it possible to merge it into new object of type B with N+x fields?

假设我们有一个

的实例
struct Message {
    char * topic;
    int topicLength;

    void * data;
    int dataLength;
};

并且我们想将其重新创建为其他类型的对象

struct CoreMessage {
    int messaageId;

    char * topic;
    int topicLength;

    void * data;
    int dataLength;

    char * senderId;
    int senderIdLength;
};

我们可以安全地将Message A变成CoreMessage B吗? C 中的东西没有复制内容,类型部分重叠,如此处所示?

不确定 "safely turn" 是什么意思,但我希望答案是 "no"。结构不同,当然不能指望较小的结构神奇地扩展到它以前没有使用过的内存中。

C中没有"overlapping types"的概念

你当然可以用Message来声明CoreMessage,但这对从较小类型到较大类型的反向转换没有任何帮助,除非传递共享信息更简单:

struct CoreMessage {
  int messageId;
  struct Message message;
  char *senderId;
  int senderIdLength;
};

现在如果我们有:

struct Message a = { ... }; /* fully initialized */
struct CoreMessage b; /* we want to convert Message into this */

我们可以做到:

b.messageId = 4711;
b.message = a; /* Copy all Message data over. */
b.senderId = "foo";
b.senderIdLength = 3;

这里没有什么是自动的,你必须自己做。

我不确定 "turn into" 是什么意思。我不确定你如何才能让演员为你做这件事。

但是,C 标准允许编译器将未使用的 space 放在结构的字段之间,因此,通常没有什么是真正有效的。您可以使 "CoreMessage" 包含一个 "Message" 并通过一次赋值产生您的结果。

不,你不能按照你的要求去做。但是,如果您愿意像这样更改 struct CoreMessage 的布局,您可以接近:

struct CoreMessage {
    struct Message message;

    int messaageId;

    char * senderId;
    int senderIdLength;
};

请注意 struct CoreMessage 然后包含一个实际的 struct Message 作为成员(而不是指向一个的指针)。然后,给出...

struct CoreMessage cm;
struct CoreMessage *cmp = &cm;
struct Message *mp = &cm.message;

...你有 (void *) cmp == (void *) mp,这对你可能想做的某些事情很有用。这也会根据 struct Message.

的更改自动调整

或者,您可以这样做:

struct Message {
    char * topic;
    int topicLength;

    void * data;
    int dataLength;

    maximum_alignment_requirement_t resv1;
    char resv2[AS_MANY_BYTES_AS_ANY_MESSAGE_TYPE_MAY_NEED_INCLUDING_PADDING];
};

struct CoreMessage {
    char * topic;
    int topicLength;

    void * data;
    int dataLength;

    maximum_alignment_requirement_t resv1;

    int messaageId;

    char * senderId;
    int senderIdLength;
};

struct Message msg;
struct CoreMessage *cmp = (struct CoreMessage *) &msg;

这很有可能会像您希望的那样工作(并且一些系统接口几乎就是这样工作的)但是 C 不保证那些相应的元素将被布置在两种不同的 struct 类型中采用相同的方式。

还要注意,我将 CoreMessage.messageId 移到与 struct Message 相对应的成员之后并非偶然。如果不这样做,很难安排相应的布局,第一个选择的指针值等价取决于它。

你可以用匿名 structures/unions 伪造这个。无可否认,自 C11 以来,匿名结构才被标准化,但许多流行的编译器长期以来一直支持它们作为扩展。

这就是这些,诚然不太漂亮,行:

struct Message  {
    char * topic;
    int topicLength;
    void * data;
    int dataLength;
    char * senderId;
    int senderIdLength;
};

struct CoreMessage {
    int messageId;
    union {
        struct Message;
        struct Message message;
    };
};