问题描述
在宏中,我希望使值具有相同的宽度,但无符号。因此,自然而然地想到了 unsigned typeof(x)
。但是,它不会编译:
/home/guest/mc.c: In function ‘main’:
/home/guest/mc.c:14:36: error: expected ‘)’ before ‘typeof’
14 | *((unsigned typeof(minus)*)&minus));
我想知道为什么会这样?也许我做错了什么?我可以以某种方式将 unsigned
添加到变量的类型吗?
附注。我注意到,类似的演员添加 const
工作正常:
#define add_const(x) ((const typeof(x))(x))
此外,添加 *
来创建指针类型也可以。
解决方法
看起来唯一的方法是在泛型选择中枚举所有“有趣”的类型。
#define to_unsigned(x) _Generic((x),\
char: (unsigned char )(x),\
signed char: (unsigned char )(x),\
int: (unsigned int )(x),\
short: (unsigned short )(x),\
long: (unsigned long )(x),\
long long: (unsigned long long)(x),\
default: x)
short a;
typeof(to_unsigned(a)) ua;
这不是可移植的,因为实现可以提供更多的整数类型。然而 typeof
本身是特定于 gcc 的。由于 gcc 似乎提供所有其他标准整数类型(size_t
、uint8_t
等)作为 typedef 名称而不是单独的不同类型,因此这些情况应该涵盖所有内容。
为什么 unsigned typeof(var) 不起作用? const typeof(x) 工作正常,为什么不呢?
每个clause 6.7 of the GCC 10.2 documentation:
typeof
构造可用于任何可以使用 typedef 名称的地方。
在 C 2018 6.7 中指定的声明的 C 语法中,声明说明符被划分为类:
- 存储类说明符,例如
static
和extern
。 - 类型说明符,例如
int
和float
。 - 类型限定符,例如
const
和volatile
。 - 函数说明符,例如
inline
。 - 对齐说明符,例如
_Alignas(4)
。
第 6.7.2 条表明 typedef-name 是一个类型说明符。第 2 段规定了它们的使用方式。它给出了允许的组合列表,包括:
-
int
、signed
或signed int
-
unsigned
或unsigned int
- typedef 名称
因此,unsigned
只能用于此列表中显示的特定组合,例如 unsigned long long
。 typedef 名称本身显示为一个项目,没有 unsigned
。因此它不能与 unsigned
一起使用。
相比之下,const
是一个限定符,它是一种不同种类的说明符,6.7的其他条款允许不同种类的说明符混合使用(有一些额外的限制在这里不相关,例如最多有一个存储类说明符)。
unsigned typeof(x)
不起作用而 const typeof(x)
起作用的根本原因是 unsigned
和 const
是两个不同的语法组件。 unsigned
是类型说明符,而 const
是类型限定符。
类型说明符列表(请注意,裸 unsigned
在语法上等同于 unsigned int
:
1. 语法
type-specifier:
void
char
short
int
long
float
double
signed
unsigned
_Bool
_Complex
atomic-type-specifier
struct-or-union-specifier
enum-specifier
typedef-name
2. 约束
...
- 无符号或无符号整数
所以 unsigned typeof(x)
相当于 unsigned int typeof(x)
。
const
是一个类型限定符:
1. 语法
type-qualifier:
const
restrict
volatile
_Atomic
const char
是正确的 C 代码,假设 x
是 char
。 unsigned int char
不是正确的 C 代码。