30

我有一个例子,其中保证了类型的对齐, union max_align 。我正在寻找一个实际使用联合的更简单的例子来解释我的朋友。

4

18 回答 18

33

我通常在解析文本时使用联合。我使用这样的东西:

typedef enum DataType { INTEGER, FLOAT_POINT, STRING } DataType ;

typedef union DataValue
{
    int v_int;
    float v_float;
    char* v_string;
}DataValue;

typedef struct DataNode
{
    DataType type;
    DataValue value;
}DataNode;

void myfunct()
{
    long long temp;
    DataNode inputData;

    inputData.type= read_some_input(&temp);

    switch(inputData.type)
    {
        case INTEGER: inputData.value.v_int = (int)temp; break;
        case FLOAT_POINT: inputData.value.v_float = (float)temp; break;
        case STRING: inputData.value.v_string = (char*)temp; break;
    }
}

void printDataNode(DataNode* ptr)
{
   printf("I am a ");
   switch(ptr->type){
       case INTEGER: printf("Integer with value %d", ptr->value.v_int); break;
       case FLOAT_POINT: printf("Float with value %f", ptr->value.v_float); break;
       case STRING: printf("String with value %s", ptr->value.v_string); break;
   }
}

如果您想了解如何大量使用联合,请使用flex / bison检查任何代码。例如看splint,它包含大量的工会。

于 2009-12-23T08:31:03.977 回答
6

我通常使用联合,您希望拥有不同的数据视图,例如 32 位颜色值,您需要 32 位 val 和红色、绿色、蓝色和 alpha 分量

struct rgba
{
  unsigned char r;
  unsigned char g;
  unsigned char b;
  unsigned char a;
};

union  
{
  unsigned int val;
  rgba components;
}colorval32;

注意您也可以通过位掩码和移位来实现相同的目的,即

#define GETR(val) ((val&0xFF000000) >> 24)

但我发现联合方法更优雅

于 2009-12-23T08:34:16.623 回答
5

要通过将特定端口映射到内存来按字节和按位访问寄存器或 I/O 端口,请参见以下示例:

    typedef Union
{
  unsigned int a;
struct {
  unsigned bit0 : 1,
           bit1 : 1,
           bit2 : 1,
           bit3 : 1,
           bit4 : 1,
           bit5 : 1,
           bit6 : 1,
           bit7 : 1,
           bit8 : 1,
           bit9 : 1,
           bit10 : 1,
           bit11 : 1,
           bit12 : 1,
           bit13 : 1,
           bit14 : 1,
           bit15 : 1
} bits;
} IOREG;

# define PORTA (*(IOREG *) 0x3B)
...
unsigned int i = PORTA.a;//read bytewise
int j = PORTA.bits.bit0;//read bitwise
...
PORTA.bits.bit0 = 1;//write operation
于 2009-12-23T08:33:17.903 回答
3

在 Windows 世界中,unions通常用于实现标记变体,它们是(或曾经是,在 .NET 之前?)在COM 对象之间传递数据的一种标准方式。

这个想法是,一个union类型可以提供一个单一的自然接口,用于在两个对象之间传递任意数据。某些 COM 对象可能会传递给您一个变体(例如 typeVARIANT_variant_t),其中可能包含 a doublefloatint或其他任何内容。

如果您必须在 Windows C++ 代码中处理 COM 对象,您会在各处看到变体类型。

于 2009-12-23T20:13:36.927 回答
2
struct cat_info
{
int legs;
int tailLen;
};

struct fish_info
{
bool hasSpikes;
};


union 
{
fish_info fish;
cat_info cat;
} animal_data;

struct animal
{
char* name;
int animal_type;
animal_data data;
};
于 2009-12-23T08:17:24.197 回答
2

SDL 使用联合来表示事件:http ://www.libsdl.org/cgi/docwiki.cgi/SDL_Event 。

于 2010-01-29T18:25:00.050 回答
2

如果您有不同类型的消息,则联合很有用,在这种情况下,您不必在任何中间级别知道确切的类型。只有发送者和接收者需要解析消息的实际消息。任何其他级别只需要知道大小以及可能的发送者和/或接收者信息。

于 2009-12-23T08:58:34.163 回答
1

我有时以这种方式使用工会

//Define type of structure
typedef enum { ANALOG, BOOLEAN, UNKNOWN } typeValue_t;
//Define the union
typedef struct  {
  typeValue_t typeValue;
  /*On this structure you will access the correct type of
    data according to its type*/
  union {
    float ParamAnalog;
    char  ParamBool;
  };
} Value_t;

然后你可以声明不同类型值的数组,或多或少有效地存储数据,并进行一些“polimorph”操作,例如:

 void printValue ( Value_t value ) {
    switch (value.typeValue) {
       case BOOL:
          printf("Bolean: %c\n", value.ParamBool?'T':'F');
          break;
       case ANALOG:
          printf("Analog: %f\n", value.ParamAnalog);
          break;
       case UNKNOWN:
          printf("Error, value UNKNOWN\n");
          break;
    }
 }
于 2009-12-23T11:12:33.857 回答
1

这是联合可能有用的另一个示例。

(不是我自己的想法,我在讨论 C++ 优化的文档中找到了这个)

开始报价

....工会也可以用来节省空间,例如

首先是非工会方法:

void F3(bool useInt) {
    if (y) {
        int a[1000];
        F1(a);  // call a function which expects an array of int as parameter
    }
    else {
        float b[1000];
        F2(b);  // call a function which expects an array of float as parameter
    }
}

这里可以为 a 和 b 使用相同的内存区域,因为它们的生存范围不重叠。您可以通过将 a 和 b 加入并集来节省大量cpu-cache 空间:

void F3(bool useInt) {

    union {
        int a[1000];
        float b[1000];
    };

    if (y) {
        F1(a);  // call a function which expects an array of int as parameter
    }
    else {
        F2(b);  // call a function which expects an array of float as parameter
    }
}

当然,使用联合不是一种安全的编程习惯,因为如果 a 和 b 的使用重叠,编译器不会发出警告。您应该只对占用大量缓存空间的大对象使用此方法。...

结束语

于 2009-12-23T19:25:32.767 回答
1
  • 读取需要强制转换为特定类型的序列化数据时。
  • lexto返回语义值时yacc。( yylval)
  • 在实现多态类型时,尤其是读取 DSL 或通用语言的类型
  • 在实现专门调用旨在采用不同类型的函数的调度程序时。
于 2009-12-24T17:19:55.393 回答
1

最近我想我看到了向量编程中使用的一些联合。矢量编程用于英特尔 MMX 技术、GPU 硬件、IBM 的 Cell 宽带引擎等。

一个向量可能对应一个 128 位的寄存器。它非常常用于SIMD架构。由于硬件具有 128 位寄存器,因此您可以在寄存器/变量中存储 4 个单精度浮点数。构造、转换、提取向量的单个元素的一种简单方法是使用联合。

typedef union {
    vector4f vec; // processor-specific built-in type
    struct { // human-friendly access for transformations, etc
        float x;
        float y;
        float z;
        float w;
    };
    struct { // human-friendly access for color processing, lighting, etc
        float r;
        float g;
        float b;
        float a;
    };
    float arr[4]; // yet another convenience access
} Vector4f;

int main()
{
    Vector4f position, normal, color;
    // human-friendly access
    position.x = 12.3f;
    position.y = 2.f;
    position.z = 3.f;
    position.w = 1.f;

    // computer friendly access
    //some_processor_specific_operation(position.vec,normal.vec,color.vec);
    return 0;
}

如果您选择 PlayStation 3 多核编程或图形编程,那么您很有可能会遇到更多此类问题。

于 2010-01-29T18:17:05.153 回答
1

我知道我参加聚会有点晚了,但作为一个实际示例Variant,我相信 VBScript 中的数据类型是作为Union. 以下代码是取自一篇文章的简化示例,否则在此处找到

struct tagVARIANT
{
    union 
    {
        VARTYPE vt;
        WORD wReserved1;
        WORD wReserved2;
        WORD wReserved3;
        union 
        {
            LONG lVal;
            BYTE bVal;
            SHORT iVal;
            FLOAT fltVal;
            DOUBLE dblVal;
            VARIANT_BOOL boolVal;
            DATE date;
            BSTR bstrVal;
            SAFEARRAY *parray;
            VARIANT *pvarVal;
        };
    };
};

实际实现(如文章所述)可在oaidl.h C 头文件中找到。

于 2010-11-25T13:04:03.790 回答
1

你的意思是这样的吗?

union {
   long long a;
   unsigned char b[sizeof(long long)];
} long_long_to_single_bytes;

添加

我最近在我们的 AIX 机器上使用它来将 64 位机器标识符转换为字节数组。

std::string getHardwareUUID(void) {
#ifdef AIX
   struct xutsname m; // aix specific struct to hold the 64bit machine id
   unamex(&b);        // aix specific call to get the 64bit machine id
   long_long_to_single_bytes.a = m.longnid;
   return convertToHexString(long_long_to_single_bytes.b, sizeof(long long));
#else // Windows or Linux or Solaris or ...
   ... get a 6byte ethernet MAC address somehow and put it into mac_buf
   return convertToHexString(mac_buf, 6);
#endif
于 2009-12-23T08:00:14.020 回答
0

可以在 中找到许多联合的示例<X11/Xlib.h>。很少有其他人在某些 IP 堆栈中(<netinet/ip.h>例如在 BSD 中)。

作为一般规则,协议实现使用联合构造。

于 2009-12-23T09:26:53.860 回答
0

为方便起见,我使用联合让我使用同一个类来存储 xyzw 和 rgba 值

#ifndef VERTEX4DH
    #define VERTEX4DH

    struct Vertex4d{

        union {
            double x;
            double r;
        };
        union {
            double y;
            double g;
        };
        union {
            double z;
            double b;
        };
        union {
            double w;
            double a;
        };

        Vertex4d(double x=0, double y=0,double z=0,double w=0) : x(x), y(y),z(z),w(w){}
    };

#endif
于 2009-12-23T08:40:26.887 回答
0

另一个例子更多:为了节省做铸件。

typedef union {
  long int_v;
  float float_v;
} int_float;

void foo(float v) {
  int_float i;
  i.float_v = v;
  printf("sign=%d exp=%d fraction=%d", (i.int_v>>31)&1, ((i.int_v>>22)&0xff)-128, i.int_v&((1<<22)-1));
}

代替:

void foo(float v) {
  long i = *((long*)&v);
  printf("sign=%d exp=%d fraction=%d", (i>>31)&1, ((i>>22)&0xff)-128, i&((1<<22)-1));
}
于 2009-12-23T08:30:45.243 回答
0

在键入双关语时,联合也很有用,这在少数几个地方是可取的(例如浮点比较算法的一些技术)。

于 2009-12-23T19:59:13.187 回答
0

例子:

使用不同的套接字类型时,但您希望引用一个通用类型。

于 2009-12-23T08:00:47.530 回答