如何在 C 中将联合指针作为参数传递? Union的内部是什么?

发布于 2024-12-08 09:45:11 字数 1029 浏览 2 评论 0原文

我有一个关于 c 中的 union 的问题。以下代码是服务器端,我们从客户端接收Signal2,在服务函数中,我可以像这样检查信号类型:data_p->header.type >?在 switch 情况下,我如何将参数传递给函数 printInfo(),它的参数是指向联合体的指针,如何传递?最后一个问题是指向联合体的指针,指向什么?联合体内部是什么,当分配这三个结构体时,它们如何适合联合体(具有大结构体的大小)?

   union
    {
        Header  header;
        Signal1 signal1;
        Signal2 signal2;
    } Data;

struct Header 
{   
    int type:
    int protocol;
    int clientId;
    int serverId;
};


struct Signal1
{
    int type:
    int protocol;
    int clientId;
    int serverId;
    char[80] something;
};


struct Signal2
{
    int type:
    int protocol;
    int clientId;
    int serverId;
    int[100] something;
};


void service(Data* data_p) {

    switch(data_p->header.type) {
        case 1:
            printInfo(&data_p->header);
        case 2:
            printInfo(data_p->header);
        case 3:
            data_p->signal2->something[5];
    }   
}


void printInfo(Data* data_p) 
{
    data_p->header.primitive;
}

I have a question about union in c. The following code is the server side, we receive Signal2 from the client side, in the service function, can I check the signal type like this: data_p->header.type? and in the switch case, how could I pass the parameter to function printInfo(), the parameter of it is the pointer to the union, how to pass? And the last question is the pointer to the union, point to what? and what is inside of the union, when these three structs are allocated, how could they fit into the union(with the size of the large struct)?

   union
    {
        Header  header;
        Signal1 signal1;
        Signal2 signal2;
    } Data;

struct Header 
{   
    int type:
    int protocol;
    int clientId;
    int serverId;
};


struct Signal1
{
    int type:
    int protocol;
    int clientId;
    int serverId;
    char[80] something;
};


struct Signal2
{
    int type:
    int protocol;
    int clientId;
    int serverId;
    int[100] something;
};


void service(Data* data_p) {

    switch(data_p->header.type) {
        case 1:
            printInfo(&data_p->header);
        case 2:
            printInfo(data_p->header);
        case 3:
            data_p->signal2->something[5];
    }   
}


void printInfo(Data* data_p) 
{
    data_p->header.primitive;
}

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

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

发布评论

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

评论(6

如果没结果 2024-12-15 09:45:11

在您的示例中,您似乎希望依赖 Header、Signal1、Signal2 中的类型、协议、clientId、serverId 字段将以相同方式对齐这一事实。但 C 或 C++ 标准中没有任何内容可以保证这一点。所以它可能适用于大多数 C 编译器,但它是一种 hack,这种 hack 是不必要的。

看起来这样做会更好,如下所示:

struct Header 
{
    int type:
    int protocol;
    int clientId;
    int serverId;
};

struct Signal1
{
    char something[80];
};

struct Signal2
{
    char something[100];
};

struct Message
{
    struct Header header;
    union
    {
        struct Signal1 signal1;
        struct Signal2 signal2;
    } payload;
};

至于你的最后一个问题,如果我理解正确的话,联合会为其最大的成员分配足够的内存,并在最严格的成员边界上对齐,并且在任何时间点都包含其成员之一的有效数据(但没有任何信息表明哪个是正确的)。指向 union 的指针是该内存区域的起始地址。

In your example it looks like you want to rely on the fact that the type, protocol, clientId, serverId fields from Header, Signal1, Signal2 will be aligned the same way. But nothing in the C or C++ standard guarantees that AFAIK. So it would probably work with most C compilers but it is a hack, where such a hack is not necessary.

It seems like it would be better to do things as follows :

struct Header 
{
    int type:
    int protocol;
    int clientId;
    int serverId;
};

struct Signal1
{
    char something[80];
};

struct Signal2
{
    char something[100];
};

struct Message
{
    struct Header header;
    union
    {
        struct Signal1 signal1;
        struct Signal2 signal2;
    } payload;
};

As for your last question if I understand it correctly, the union is allocated enough memory for the largest of it's members, and aligned at the strictest of it's members' boundaries, and at any point in time contains valid data for one of it's members (but nothing indicating which is the correct one). And the pointer to union is the address of the start of that memory area.

沙与沫 2024-12-15 09:45:11

我认为你的联合声明是没有按预期工作的部分。

尝试以下操作。

union Data
{
    Header  header;
    Signal1 signal1;
    Signal2 signal2;
};

这应该创建一个名为 Data 的联合类型,而不是匿名联合类型的单个变量。

从这里,即使通过 data_p->header.Type 传递 Signal2 对象,您也应该能够访问 Header

I think your declaration of the union is the part that isn't working as expected.

Try the following.

union Data
{
    Header  header;
    Signal1 signal1;
    Signal2 signal2;
};

This should make a union type called Data instead of a single variable of an anonymous union type.

From here you should be able access the Header even when passed a Signal2 object via data_p->header.Type.

银河中√捞星星 2024-12-15 09:45:11

类似的东西

enum{Header,Signal1,Signal2} type = Header;

....
union Data
{
    Header header;
    Signal1 signal1;
    Signal2 signal2;
};

struct Packet
{
    type data_type; // points to one of Header, Signal1 or Signal2
    union Data data;
};

可能是将指针传递给联合所持有的内容的好方法。

或者处理联合的函数的另一个参数,或者全局变量,或者配置参数。据我所知,工会的主张必须明确告知。

Something like

enum{Header,Signal1,Signal2} type = Header;

....
union Data
{
    Header header;
    Signal1 signal1;
    Signal2 signal2;
};

struct Packet
{
    type data_type; // points to one of Header, Signal1 or Signal2
    union Data data;
};

could be a good way of passing the pointer to what the union holds.

Or another argument to the function that processes the union, or a global variable, or a configuration parameter. As far as I know, what a union holds has to be explicitly told.

思慕 2024-12-15 09:45:11

我认为联合中的头结构意味着变量的公共前缀。所以你可以像这样检查这个联合的类型:

 switch(data_p->header.type) {
     case 1:
         printInfo(data_p);
     case 2: //unknown type?
         printInfo(data_p);
     case 3: // type is obviously signal2
         data_p->signal2->something[5];
 }   

所以是的,你可以用 data_p->header.type 检查。在我看来,你可以稍微重写一下代码,让它更明显,

enum { 
  HEADER_TYPE  = 1, // fill in the correct type numbers here to match the documentation
  SIGNAL1_TYPE = 2,
  SIGNAL2_TYPE = 3
};
switch(data_p->header.type) {
    case 1:
        printInfo(data_p);
    case 2: //unknown type?
        printInfo(data_p);
    case SIGNAL2_TYPE: // type is obviously signal2
        data_p->signal2->something[5];
}   

我在 printInfo 标头中注意到的另一件事没有一个名为 Primitive 的变量
从 switch 语句中,您可以使用 printInfo(data_p) 来正确调用它。

这里最重要的是,程序员必须确保类型变量始终设置为正确的值,对应于联合部分的正确结构。
即,如果结构是 signal1,则为 1,如果是 signal2,则为 2,依此类推。

但是,联合的使用在这里毫无用处,因为除了最后一个字段之外,所有字段都是相同的,并且标头显然意味着访问公共字段。

struct Header
{
  int type:
  int protocol;
  int clientId;
  int serverId;
};

struct Signal1
{
  struct Header header;
  int[80] something;
};

struct Signal2
{
  struct Header header;
  int[100] something;
};

enum { 
  SIGNAL1_TYPE = 0,
  SIGNAL2_TYPE
};

void service(struct Header* data_p) {

  switch(data_p->header.type) {
    default:
        printInfo(data_p);
      break;
    case SIGNAL1_TYPE:
        /* your code here */
        call_func( (struct Signal1 *) data_p );
      break;
    case SIGNAL2_TYPE:
        /* your code here */
        call_func( (struct Signal2 *) data_p );
      break;
  }   

}

I think the header structure in the union is meant to be the common prefix of variables. so you would check the type of this union like this:

 switch(data_p->header.type) {
     case 1:
         printInfo(data_p);
     case 2: //unknown type?
         printInfo(data_p);
     case 3: // type is obviously signal2
         data_p->signal2->something[5];
 }   

So yes you can check with data_p->header.type. it seems to me that you could rewrite the code a little to get it more obvious

enum { 
  HEADER_TYPE  = 1, // fill in the correct type numbers here to match the documentation
  SIGNAL1_TYPE = 2,
  SIGNAL2_TYPE = 3
};
switch(data_p->header.type) {
    case 1:
        printInfo(data_p);
    case 2: //unknown type?
        printInfo(data_p);
    case SIGNAL2_TYPE: // type is obviously signal2
        data_p->signal2->something[5];
}   

the other thing i notices in printInfo header doesn't have a variable called primitive
from the switch statement you would call use printInfo(data_p) to call it correctly.

The most important thing here is that the programmer has to make sure that the type variable is always set to the correct value, corresponding to the right struct of the union part.
i.e. if the struct is a signal1 its 1 and if it is a signal2 its 2 and so on

But the use of the union is quite useless here, since all fields are identical except the last one and the header is obviously meant to access the common fields.

struct Header
{
  int type:
  int protocol;
  int clientId;
  int serverId;
};

struct Signal1
{
  struct Header header;
  int[80] something;
};

struct Signal2
{
  struct Header header;
  int[100] something;
};

enum { 
  SIGNAL1_TYPE = 0,
  SIGNAL2_TYPE
};

void service(struct Header* data_p) {

  switch(data_p->header.type) {
    default:
        printInfo(data_p);
      break;
    case SIGNAL1_TYPE:
        /* your code here */
        call_func( (struct Signal1 *) data_p );
      break;
    case SIGNAL2_TYPE:
        /* your code here */
        call_func( (struct Signal2 *) data_p );
      break;
  }   

}

森林很绿却致人迷途 2024-12-15 09:45:11

访问联合成员的语法与访问结构成员的语法非常相似。一个使用 .运算符通过普通联合和 -> 访问联合字段通过指向联合的指针访问联合字段。假设您的示例中的数据联合:

Data v;
Data *p = &v;
int ftype;

ftype = v.header.type;
ftype = p->header.type;

至于 printinfo 的参数,代码中显示的参数类型是正确的,它应该是指向 Data 的指针。但是,正如其他地方所指出的, printInfo 中的代码不正确。我希望它在标头类型字段上包含一个类似于服务方法中的开关,如下所示:

void printInfo(Data* data_p) 
{
    printf("Type %d, protocol %d, clientId %d, serverId %d ",
         data_p->header.type, data_p.header.protocol,
         data_p->header.clientId, data_p->header.serverId);

    switch(data_p->header.type) {
        case 1:
            // Signal 1
            printf("signal 1 (string): %s", data_p->signal1.something);
        case 2:
            // Signal 2
            printf("signal 2 (int array): %d", data_p->signal2.something[0]);
        // and so on
    }
    printf("\n");
}

正如其他地方所说,联合一次仅包含其成员之一。编译器为其提供了足够的空间来包含尽可能大的成员。将一种可能的数据类型存储在联合中会将数据覆盖在之前存在的数据上。

程序员必须跟踪哪些可能的元素已放入联合中,并适当地访问它。在示例中的数据联合中, header.type 字段用于此目的。

The syntax of accessing union members is very similar to that used to access structure members. One uses the . operator to access a union field through a plain union and the -> to access a union field through a pointer to union. Assuming the Data union in your example:

Data v;
Data *p = &v;
int ftype;

ftype = v.header.type;
ftype = p->header.type;

As to the parameter to printinfo, the parameter type shown in your code is correct, it should be a pointer to Data. However, the code inside printInfo is not correct, as pointed out elsewhere. I would expect it to contain a switch on the header type field similar to the one in the service method, as in the following:

void printInfo(Data* data_p) 
{
    printf("Type %d, protocol %d, clientId %d, serverId %d ",
         data_p->header.type, data_p.header.protocol,
         data_p->header.clientId, data_p->header.serverId);

    switch(data_p->header.type) {
        case 1:
            // Signal 1
            printf("signal 1 (string): %s", data_p->signal1.something);
        case 2:
            // Signal 2
            printf("signal 2 (int array): %d", data_p->signal2.something[0]);
        // and so on
    }
    printf("\n");
}

As has also been said elsewhere, a union only contains one of its members at a time. The compiler gives it enough space to contain the largest possible member. Storing one of the possible data types in a union overlays the data on whatever was there before.

The programmer must keep track of which of the possible elements has been put into a union, and access it appropriately. In the Data union in your example, the header.type field is used for this purpose.

阿楠 2024-12-15 09:45:11

你需要

像这样 专门化 printinfo()
void printinfo(Header*)

void printinfo(Signal1*)

void printinfo(Signal2*)

然后像这样传递它
案例2:
printInfo(&data_p->signal1); // 将正确的联合成员传递给正确的函数,

因此实际上您没有传递联合,而是传递联合内的数据。

第二个问题:联合不是结构。工会
具有最大成员的大小。
你应该阅读sizeof a union in C/C++

祝你好运

you need to specialize printinfo()

like
void printinfo(Header*)

void printinfo(Signal1*)

void printinfo(Signal2*)

then pass it like
case 2:
printInfo(&data_p->signal1); // pass the right union member to the right function

so really you are not passing the union, you are passing the data inside the union.

second question: Unions are not structs. unions
have the size of the largest member.
you shoudl read sizeof a union in C/C++

good luck

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文