Typedef 一个 uintX_t 类型,其中 X 是宏的值
Typedef an uintX_t type, where X is the value of a macro
我有一个宏,WW
,字宽以位为单位,比如
#define WW 64
我想声明一个新类型 foo_t
作为 <stdint.h>
中 uintX_t
之一的别名。我可以硬编码字宽并使用
#define uint(x) typedef uint ## x ## _t foo_t
uint(64);
但是,uint(WW)
显然是错误的。我已经使用 #define expand(x) x
这样的宏玩了一段时间,并以各种方式使用它,但无济于事。我的最后一招是 #if
级联,例如
#if WW == 64
typedef uint64_t foo_t;
#elif WW == 32
typedef uint32_t foo_t;
#elif WW == 16
typedef uint16_t foo_t;
#elif WW == 8
typedef uint8_t foo_t;
#else
#error "unsupported word width"
#endif
我宁愿避免。有没有一种方法可以根据我的 WW
宏对类型进行类型定义,以便 uint(WW)
最终扩展为 uint64_t
?我相信答案是"no",但一些语言律师请证明我错了。
由于宏扩展的工作方式,您需要额外的间接级别:
#define maketype(x) uint ## x ## _t
#define uint(x) typedef maketype(x) foo_t
来自 C11dr n1570:
6.10.3.1 Argument substitution
After the arguments for the invocation of a function-like macro have been identified,
argument substitution takes place. A parameter in the replacement list, unless preceded
by a #
or ##
preprocessing token or followed by a ##
preprocessing token (see below), is
replaced by the corresponding argument after all macros contained therein have been
expanded. Before being substituted, each argument’s preprocessing tokens are
completely macro replaced as if they formed the rest of the preprocessing file; no other
preprocessing tokens are available.
基本上,你需要通过一个调用宏来做扩展:
#define WW 64
/* The macro that creates the typedef. */
#define uint_(x) typedef uint ## x ## _t foo_t
/* Replaces uint(x) with uint_(<expansion of x>). */
#define uint(x) uint_(x)
/* Replaces x with <expansion of x>. */
#define expand(x) x
uint(WW);
expand(uint_(WW));
结果
typedef uint64_t foo_t;
typedef uintWW_t foo_t;
在 expand(uint_(WW))
的情况下,它扩展到它的唯一参数,意味着 expand(uint_(WW))
变成 uint_(WW)
。因为它是单个预处理标记的一部分,所以 WW
不会展开。出于这个原因,您可以 expand(expand(expand(uint_(WW))))
,但它仍然不起作用。
在uint(WW)
的情况下,扩展为uint_(WW)
。但是,上面的段落指出 uint
的参数受宏替换的影响,因此结果实际上是 uint_(<expansion of WW>)
因为参数 WW
被宏替换了。然后 uint_
宏被替换为 WW
.
的值调用
将 WW
直接传递给负责 typedef
的宏不起作用的原因是因为 WW
是涉及标记粘贴的表达式的一部分(##
). "A parameter in the replacement list, unless preceded by a #
or ##
preprocessing token or followed by a ##
preprocessing token ..., is replaced..." 基本上这意味着 ##
阻止扩展。
出于同样的原因,您也不能使用 uint_(expand(WW))
:typedef uintexpand(WW)_t foo_t
看起来不完全正确,是吗?
您还可以通过更通用的 PASTE3
宏来完成此操作:
#define WW 64
#define PASTE3(x, y, z) PASTE3_(x, y, z)
#define PASTE3_(x, y, z) x ## y ## z
PASTE3(typedef uint, WW, _t foo_t);
此外,请记住,因为 WW
本身就是一个表达式,所以它将被完全替换为宏。这意味着无论有多少层替换,它都会扩展,除非 #
或 ##
停止扩展当然:
/* Try not to do silly things like this... */
#define YY(x) 6 ## x
#define WW YY(4)
#define PASTE3(x, y, z) PASTE3_(x, y, z)
#define PASTE3_(x, y, z) x ## y ## z
PASTE3(typedef uint, WW, _t foo_t);
结果:
typedef uint64_t foo_t;
我有一个宏,WW
,字宽以位为单位,比如
#define WW 64
我想声明一个新类型 foo_t
作为 <stdint.h>
中 uintX_t
之一的别名。我可以硬编码字宽并使用
#define uint(x) typedef uint ## x ## _t foo_t
uint(64);
但是,uint(WW)
显然是错误的。我已经使用 #define expand(x) x
这样的宏玩了一段时间,并以各种方式使用它,但无济于事。我的最后一招是 #if
级联,例如
#if WW == 64
typedef uint64_t foo_t;
#elif WW == 32
typedef uint32_t foo_t;
#elif WW == 16
typedef uint16_t foo_t;
#elif WW == 8
typedef uint8_t foo_t;
#else
#error "unsupported word width"
#endif
我宁愿避免。有没有一种方法可以根据我的 WW
宏对类型进行类型定义,以便 uint(WW)
最终扩展为 uint64_t
?我相信答案是"no",但一些语言律师请证明我错了。
由于宏扩展的工作方式,您需要额外的间接级别:
#define maketype(x) uint ## x ## _t
#define uint(x) typedef maketype(x) foo_t
来自 C11dr n1570:
6.10.3.1 Argument substitution
After the arguments for the invocation of a function-like macro have been identified, argument substitution takes place. A parameter in the replacement list, unless preceded by a
#
or##
preprocessing token or followed by a##
preprocessing token (see below), is replaced by the corresponding argument after all macros contained therein have been expanded. Before being substituted, each argument’s preprocessing tokens are completely macro replaced as if they formed the rest of the preprocessing file; no other preprocessing tokens are available.
基本上,你需要通过一个调用宏来做扩展:
#define WW 64
/* The macro that creates the typedef. */
#define uint_(x) typedef uint ## x ## _t foo_t
/* Replaces uint(x) with uint_(<expansion of x>). */
#define uint(x) uint_(x)
/* Replaces x with <expansion of x>. */
#define expand(x) x
uint(WW);
expand(uint_(WW));
结果
typedef uint64_t foo_t;
typedef uintWW_t foo_t;
在 expand(uint_(WW))
的情况下,它扩展到它的唯一参数,意味着 expand(uint_(WW))
变成 uint_(WW)
。因为它是单个预处理标记的一部分,所以 WW
不会展开。出于这个原因,您可以 expand(expand(expand(uint_(WW))))
,但它仍然不起作用。
在uint(WW)
的情况下,扩展为uint_(WW)
。但是,上面的段落指出 uint
的参数受宏替换的影响,因此结果实际上是 uint_(<expansion of WW>)
因为参数 WW
被宏替换了。然后 uint_
宏被替换为 WW
.
将 WW
直接传递给负责 typedef
的宏不起作用的原因是因为 WW
是涉及标记粘贴的表达式的一部分(##
). "A parameter in the replacement list, unless preceded by a #
or ##
preprocessing token or followed by a ##
preprocessing token ..., is replaced..." 基本上这意味着 ##
阻止扩展。
出于同样的原因,您也不能使用 uint_(expand(WW))
:typedef uintexpand(WW)_t foo_t
看起来不完全正确,是吗?
您还可以通过更通用的 PASTE3
宏来完成此操作:
#define WW 64
#define PASTE3(x, y, z) PASTE3_(x, y, z)
#define PASTE3_(x, y, z) x ## y ## z
PASTE3(typedef uint, WW, _t foo_t);
此外,请记住,因为 WW
本身就是一个表达式,所以它将被完全替换为宏。这意味着无论有多少层替换,它都会扩展,除非 #
或 ##
停止扩展当然:
/* Try not to do silly things like this... */
#define YY(x) 6 ## x
#define WW YY(4)
#define PASTE3(x, y, z) PASTE3_(x, y, z)
#define PASTE3_(x, y, z) x ## y ## z
PASTE3(typedef uint, WW, _t foo_t);
结果:
typedef uint64_t foo_t;