sizeof(…) 运算符的使用引发困惑的结果

3

最近我正在浏览 一些C++代码,并遇到了以下行代码

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

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

然而,当我尝试使用一个简单的代码片段程序来计算表达式 sizeof((struct sockaddr_un*)0)->sun_path 时,它产生了 sockaddr_un 结构体成员 sun_path 的大小。

显然,这是原始行作者的意图; 但我发现它在语法上很令人困惑,因为它看起来像对 sizeof(...) 操作的结果进行指针解引用。

我对 sizeof(...) 的使用有什么误解吗? 为什么这个表达式会这样评估?


1
请查看参考文献。有两种形式。代码应该真正有一个空格,因为这样很误导人。 - chris
2
@chris 哦,我想我明白了 - 与sizeof(type)不同,sizeof表达式形式没有括号,因此添加的任何括号都是表达式的一部分。 - fish2000
1
如果您能使用它,我建议使用std::declval,它传达的意义更好,而且不像可怕的空指针解引用。 - user975989
1
我很惊讶没有人提到sizeof表达式不会在运行时评估表达式,因此您可以编写任何语法正确的表达式,即使是未定义行为的表达式...这就是为什么在这里“解引用空指针”是正确的原因,因为没有真正的解引用,只有一个具有类型但从未被机器实际评估的表达式。 - Jean-Baptiste Yunès
1
只需尝试 sizeof ( cout << "hello" << endl ); - Jean-Baptiste Yunès
显示剩余5条评论
2个回答

4
你的错误在于认为sizeof像函数调用一样工作,而实际上它是一个运算符。根本不需要使用()sizeof实际上是一个形式为sizeof expression的运算符,expression周围的()不是必须的。表达式中sizeof的优先级等同于++--(前缀形式)、一元+-!~(逻辑和位非)、(type)类型转换、&(地址)、一元*(指针间接)和(C从2011年起) _Alignof。所有这些都具有从右到左的结合性。
唯一比sizeof优先级更高的运算符是++--(后缀形式)、函数调用(())、[]数组下标、.->以访问结构体成员以及(仅限于1999年的C)复合文字(type){list}
没有sizeof(expression)形式。 sizeof x计算表达式x的结果大小(而不计算x)。 sizeof (x)计算表达式(x)的结果大小,同样不计算它。你恰好有一个形如sizeof a->b的表达式,由于优先级规则,它等同于sizeof (a->b)而不是sizeof(a)->b(这将触发编译错误)。

没错 - sizeof(a)->b 看起来像是这样的东西,这是我最初困惑的根源;我感谢在这种情况下运算符优先级规则的澄清,谢谢。 - fish2000

4
在C++中,sizeof运算符除了常见的sizeof(type)形式外,还有一个sizeof expression形式。因此,下面这个表达式:
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(type)形式,但实际上它是应用于括号表达式的sizeof expression形式。
唯一不能做的就是sizeof type,所以这是无效的
sizeof decltype(((struct sockaddr_un*)0)->sun_path)

在C++中,获取结构体字段的更现代方法是使用declval,而不需要将0转换为指针:

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

实际上,根据cppreference.com文档,带括号的形式用于检索类型的大小;没有括号,则计算_expression_的大小 - 因此,如果您有像sizeof(_expression_)这样的东西,则括号实际上包含在_expression_中,因为它是没有括号的非类型形式的sizeof...之所以这非常令人困惑,是因为sizeof(...)看起来像一个函数调用,但它不是,它是一个运算符 - 即使运算符的一种形式看起来更像函数调用。 - fish2000
啊哈,谢谢,你示例中的 decltype 在这种情况下使得它非常清晰明了。 - fish2000
2
您IP地址为143.198.54.68,由于运营成本限制,当前对于免费用户的使用频率限制为每个IP每72小时10次对话,如需解除限制,请点击左下角设置图标按钮(手机用户先点击左上角菜单按钮)。 - Jonathan Leffler

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接