混淆使用 sizeof(…) 运算符结果

Confusing use of sizeof(…) operator results

我正在浏览 some C++ code recently and I ran into the following line:

static char zsocket_name[sizeof((struct sockaddr_un*)0)->sun_path] = {};

... 这令人困惑,因为在我看来,sizeof 运算符的结果似乎正在被指针解引用以访问名为 sun_path 的结构字段,并且该值将是用于调整静态存储中数组的大小。

但是,当我尝试 a simple snippet program 计算表达式 sizeof((struct sockaddr_un*)0)->sun_path 时,它会产生 sockaddr_un 结构的 sun_path 成员的大小。

很明显,这就是原文作者的意图;但我发现它在语法上令人困惑,因为它看起来像是对 sizeof(…) 操作结果的指针取消引用。

关于 sizeof(…) 的这种用法,我遗漏了什么?为什么这个表达式会这样计算?

在 C++ 中,sizeof operator 除了更常见的 之外,还有一种形式 <code>sizeof <em>expression</em> sizeof(type), 所以这个:

sizeof ((struct sockaddr_un*)0)->sun_path

相当于:

sizeof(decltype(((struct sockaddr_un*)0)->sun_path))

前者,尽管没有空格,是您发布的代码中所写的内容。


请注意,带括号的表达式也是表达式,因此 sizeof ((struct sockaddr_un*)0)->sun_path 也可以写成带有额外的括号:sizeof(((struct sockaddr_un*)0)->sun_path) — 尽管这看起来像 sizeof(<em>type</em>)形式,实际上是sizeof <em>expression</em>形式应用于括号表达式。

你唯一不能做的就是sizeof <em>type</em>,所以这是无效:

sizeof decltype(((struct sockaddr_un*)0)->sun_path)

在不将 0 强制转换为指针的情况下,在 C++ 中获取结构字段的一种更现代的方法是使用 declval:

sizeof std::declval<sockaddr_un>().sun_path

你的错误是认为 sizeof 像函数调用一样工作,而实际上它是一个运算符。 根本不需要使用()

sizeof实际上是sizeof expression形式的运算符,不需要expression周围的() sizeof在表达式中的优先级实际上等于++--(前缀形式)、一元+-!~(逻辑和按位非),(type) 类型转换,&(地址),一元 *(指针间接),以及(2011 年的 C)_Alignof.所有这些都具有 right-to-left 关联性。

唯一比sizeof优先级高的运算符是++--(后缀形式)、函数调用(())、[]数组下标,.-> 以访问结构成员,以及(仅适用于 1999 年的 C)复合文字 (type){list}.

没有sizeof(expression)表格。 sizeof x 计算表达式 x 的结果大小(不计算 x)。 sizeof (x) 计算表达式 (x) 结果的大小,再次不计算它。您碰巧有一个 sizeof a->b 形式的表达式,它(由于优先规则)等效于 sizeof (a->b) 而不是 sizeof(a)->b (这会触发编译错误)。