C中的typeof括号是什么意思?

What does parentheses mean in typeof in C?

我正在研究Linux container_of函数,发现typeof的括号的使用很迷惑

这里是函数的代码container_of:

#define container_of(ptr, type, member) ({ \
    const typeof( ((type*)0)->member) * __mptr =(ptr);\
    (type*)( (char*)__mptr - offsetof(type,member) );})

在第二行,我们有

const typeof( ((type*)0)->member) * __mptr =(ptr);

不明白为什么要在右边加括号

网上搜了一下,找到了一些类似的用法。例如,从 https://gcc.gnu.org/onlinedocs/gcc/Typeof.html 中,我找到了一个函数 max(a,b)

#define max(a,b) 
({ typeof (a) _a = (a); \
  typeof (b) _b = (b); \
  _a > _b ? _a : _b; })

在这种情况下,我们确实有类似的用法typeof (a) _a = (a);

为什么要在右边加括号?我们可以把右边的括号去掉,变成typeof (a) _a = a;吗?

提前致谢!

当使用 container_of 宏时,我们不知道参数将用于 ptr。它可能是一个标识符名称,如 MyPointer。但它可能是一个表达式,例如 MyArray + 3.

宏中的常见做法是在替换列表中的参数周围使用括号。例如,如果我们定义 square:

#define square(x) ((x) * (x))

然后square(3+4)将替换为((3+4) * (3+4)),也就是我们想要的49。如果我们改用:

#define square(x) (x * x)

那么square(3+4)将被替换为(3+4 * 3+4),这将被评估为3 + 4*3 + 4,即3 + 12 + 4,即19,这是不需要的。

同样,在您显示的代码中,const typeof( ((type*)0)->member) * __mptr =(ptr);ptr 用于初始化名为 __mptr 的新定义对象。为了安全起见,它在括号中。它不会改变 typeof 的运作方式。

您不应删除这些括号。在这个特定的上下文中,通常不会为 ptr 传递太多会在没有括号的情况下破坏宏的内容,但是有一些理论上可能会破坏宏的表达式。

通过 #define 创建的宏执行直接标记替换。因此,在类函数宏的参数周围使用括号是一种很好的做法,因为它可以防止发生意外问题。

例如:

#define multiply(x, y) x * y

如果你在这里使用这个宏:

int z = multiply(1 + 3, 4 + 5) / 3;

您可能认为 z 包含值 12,但您会误会。

它将上面的内容扩展为:

int z = 1 + 3 * 4 + 5 / 3;

这将导致 14。使用括号可避免此问题。如果它被定义为:

#define multiply(x, y) ((x) * (y))

那么上面的例子将扩展为:

int z = ((1 + 3) * (4 + 5)) / 3;

这会给出预期的结果。