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)
在这里我使用的事实是struct
s可以直接返回,并且几乎像原始类型的值一样处理(你可以分配struct
s).
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
.
联合体也常用于语言处理器的词法分析和解析阶段,如编译器和解释器.这是我正在编辑的一个.
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
).语法生成器为根据正在处理的规则确定在任何时间存储哪个值提供了相当大的帮助.
请避免使用union进行"hacks",它们会导致可移植性问题(字节序,对齐问题).
union的合法用法是在同一个地方存储不同的数据类型,最好使用标记,以便您知道它是哪种类型.请参阅1800信息示例.
不要使用union在数据类型之间进行转换,例如从整数到几个字节.使用移位和屏蔽代替可移植性.
归档时间: |
|
查看次数: |
53056 次 |
最近记录: |