C中的联盟的例子

cla*_*laf 32 c unions

我正在寻找一些工会的例子,不是为了理解工会是如何工作的,希望我能做到,而是要看看人们对工会做了哪种黑客攻击.

所以随时分享你的工会黑客(当然有一些解释:))

unw*_*ind 37

一个经典是表示"未知"类型的值,如在简单虚拟机的核心中:

typedef enum { INTEGER, STRING, REAL, POINTER } Type;

typedef struct
{
  Type type;
  union {
  int integer;
  char *string;
  float real;
  void *pointer;
  } x;
} Value;
Run Code Online (Sandbox Code Playgroud)

使用它,您可以编写处理"值"的代码,而无需知道它们的确切类型,例如实现堆栈等.

由于这是(旧的,前C11)C,内部联合必须在外部给出一个字段名称struct.在C++中,你可以让它union是匿名的.选择这个名字可能很难.我倾向于使用单字母,因为它几乎从不单独引用,因此从上下文中总是清楚发生了什么.

将值设置为整数的代码可能如下所示:

Value value_new_integer(int v)
{
  Value v;
  v.type = INTEGER;
  v.x.integer = v;
  return v;
}
Run Code Online (Sandbox Code Playgroud)

在这里我使用的事实是structs可以直接返回,并且几乎像原始类型的值一样处理(你可以分配structs).

  • 请注意,C11 提供匿名联合,因此“因为这是 C”段落适用于 C90 和 C99,但不适用于 C11。同样清楚的是,由于这个答案是在 2009 年写的,所以不预测 C11 会提供什么是非常合理的。 (2认同)
  • @出于好奇,我在问这个问题。上面的函数不提供_redeclaration error_吗? (2认同)

180*_*ION 10

这是我每天使用的一小部分:

struct tagVARIANT {
    union {
        struct __tagVARIANT {
            VARTYPE vt;
            WORD    wReserved1;
            WORD    wReserved2;
            WORD    wReserved3;
            union {
                LONG          lVal;         /* VT_I4                */
                BYTE          bVal;         /* VT_UI1               */
                SHORT         iVal;         /* VT_I2                */
                FLOAT         fltVal;       /* VT_R4                */
                DOUBLE        dblVal;       /* VT_R8                */
                VARIANT_BOOL  boolVal;      /* VT_BOOL              */
                _VARIANT_BOOL bool;         /* (obsolete)           */
                SCODE         scode;        /* VT_ERROR             */
                CY            cyVal;        /* VT_CY                */
                DATE          date;         /* VT_DATE              */
                BSTR          bstrVal;      /* VT_BSTR              */
                IUnknown *    punkVal;      /* VT_UNKNOWN           */
                IDispatch *   pdispVal;     /* VT_DISPATCH          */
                SAFEARRAY *   parray;       /* VT_ARRAY             */
                BYTE *        pbVal;        /* VT_BYREF|VT_UI1      */
                SHORT *       piVal;        /* VT_BYREF|VT_I2       */
                LONG *        plVal;        /* VT_BYREF|VT_I4       */
                FLOAT *       pfltVal;      /* VT_BYREF|VT_R4       */
                DOUBLE *      pdblVal;      /* VT_BYREF|VT_R8       */
                VARIANT_BOOL *pboolVal;     /* VT_BYREF|VT_BOOL     */
                SCODE *       pscode;       /* VT_BYREF|VT_ERROR    */
                CY *          pcyVal;       /* VT_BYREF|VT_CY       */
                DATE *        pdate;        /* VT_BYREF|VT_DATE     */
                BSTR *        pbstrVal;     /* VT_BYREF|VT_BSTR     */
                IUnknown **   ppunkVal;     /* VT_BYREF|VT_UNKNOWN  */
                IDispatch **  ppdispVal;    /* VT_BYREF|VT_DISPATCH */
                SAFEARRAY **  pparray;      /* VT_BYREF|VT_ARRAY    */
                VARIANT *     pvarVal;      /* VT_BYREF|VT_VARIANT  */
                PVOID         byref;        /* Generic ByRef        */
                CHAR          cVal;         /* VT_I1                */
                USHORT        uiVal;        /* VT_UI2               */
                ULONG         ulVal;        /* VT_UI4               */
                INT           intVal;       /* VT_INT               */
                UINT          uintVal;      /* VT_UINT              */
                DECIMAL *     pdecVal;      /* VT_BYREF|VT_DECIMAL  */
                CHAR *        pcVal;        /* VT_BYREF|VT_I1       */
                USHORT *      puiVal;       /* VT_BYREF|VT_UI2      */
                ULONG *       pulVal;       /* VT_BYREF|VT_UI4      */
                INT *         pintVal;      /* VT_BYREF|VT_INT      */
                UINT *        puintVal;     /* VT_BYREF|VT_UINT     */
            } __VARIANT_NAME_3;
        } __VARIANT_NAME_2;
        DECIMAL decVal;
    } __VARIANT_NAME_1;
};
Run Code Online (Sandbox Code Playgroud)

这是OLE自动化变体数据类型的定义.如您所见,它有很多可能的类型.根据您预期的客户端代码的功能,您可以在不同情况下使用的类型有很多规则.并非所有语言都支持所有类型.

VT_BYREF其后的类型由VBScript等语言使用,默认情况下通过引用传递参数.这意味着如果您有一些代码关注变量结构细节(例如C++)被不具有的代码(例如VB)调用,那么如果需要,您必须小心地取消引用变量参数.

byref类型还用于从函数返回值.使用奇怪的错误名称SAFEARRAY类型也支持数组类型- 因此很难从C++中使用.

如果你有一个字符串数组,你可以将它传递给vbscript,但不能使用它(除了打印大小).要实际读取值,数组数据必须是类型VT_BYREF | VT_BSTR.

  • 天哪,我的眼睛在流血! (32认同)

Dio*_*lis 8

联合体也常用于语言处理器的词法分析和解析阶段,如编译器和解释器.这是我正在编辑的一个.

union {
    char c;
    int i;
    string *s;
    double d;
    Expression *e;
    ExpressionList *el;
    fpos_t fp;
}
Run Code Online (Sandbox Code Playgroud)

联合用于将语义值与词法分析器的标记和解析器的产生相关联.这种做法在语法生成器中很常见,例如yacc,它为它提供了明确的支持.工会可以保留其任何价值,但当时只有其中一个.例如,在输入文件的任何一点,您要么读取字符常量(存储在其中c),要么读取整数(存储在其中i)或浮点数(存储在其中d).语法生成器为根据正在处理的规则确定在任何时间存储哪个值提供了相当大的帮助.


sta*_*lue 7

请避免使用union进行"hacks",它们会导致可移植性问题(字节序,对齐问题).

  • union的合法用法是在同一个地方存储不同的数据类型,最好使用标记,以便您知道它是哪种类型.请参阅1800信息示例.

  • 不要使用union在数据类型之间进行转换,例如从整数到几个字节.使用移位和屏蔽代替可移植性.

  • @claferri 请更具体(哪个联合在哪个文件中?)。 (2认同)