【问题标题】:Why sizeof is implemented as operator not as macros为什么 sizeof 被实现为运算符而不是宏
【发布时间】:2024-01-18 13:46:01
【问题描述】:

我理解为什么 sizeof 没有实现为 Why is sizeof considered as an operator? 的函数的原因

但我不明白为什么我们需要将 sizeof 实现为 unary operator 的特殊类型,它作为编译时而不是运行时执行(我猜因为其他运算符总是作为运行时执行)

我们可以通过将 sizeof 设为宏不是来实现相同的目标吗?这样的compiled time unary operatormacros有什么区别?


我只是想知道为什么他们没有首先考虑宏,而是实施不同的运算符。当我第一次想到 sizeof() 是什么时,我认为它应该是宏。从来没有想过这样的一元运算符。

【问题讨论】:

  • 你谷歌了! compile time unary operator and macros 和有什么区别?
  • “我们可以通过将 sizeof 设为宏来实现相同的目标” - 不,你不能。 此外,C99 支持 VLA,并且评估了 sizeof 一个 VLA在运行时。
  • 作为一般规则,如果某些东西可以在编译时进行评估,它应该是。人们希望编译器做尽可能多的工作,从而减少运行时负担。
  • “其他运算符总是作为运行时执行”?真的吗?这根本不是真的。像2 + 3 * 8 这样的常量表达式需要在编译时进行评估。
  • @Mr.32 你为什么固执地坚持你的想法,它应该是一个宏?为什么应该会这样?事实上,它不应该,。首先,宏在许多方面不如运算符。它们不是类型安全的(事实上,它们根本不安全),它们令人困惑,它们会导致混乱。其次,数据类型的大小是编程语言中的一个内在概念,与其语义紧密耦合。因此,预处理器只是一个语法、纯文本工具,不能、不需要也不应该知道任何关于对象大小的事情。

标签: c macros sizeof unary-operator


【解决方案1】:

你的问题不无道理。事实上,标准库已经有一个非常相似的功能实现为宏:它是标准的offsetof 宏。另请注意,sizeof 的大部分可用性来自其编译时性质(offsetof 也是如此),这就是为什么运行时实现会显着逊色的原因。 (顺便说一句,您声称所有其他运算符“始终在运行时执行”的断言声明是完全不真实的。)

sizeof 即使在原始 C 语言中也无法实现为宏的一个原因是它应该接受 typesexpressions 作为参数.用一个宏来涵盖这两种参数是不可能的。我们至少需要两个宏:一个用于类型,一个用于表达式。但是即使我们同意将这两种形式的sizeof 分成两个不同的宏,实现一个能够正确处理表达式参数的宏仍然是相当困难的(甚至是不可能的)。

同时,如果我们将自己限制在原始 C 中(即不考虑 C99 VLA),那么我们可能会将 type 参数的 sizeof 实现为宏

#define sizeof(T) ((size_t) ((T *) 0 + 1))

这与将标准offsetof 实现为宏的技术几乎相同。

上面的宏实现仍然不完美,因为它不能正常工作,比如int[6] 参数,但你明白了。顺便说一句,这可能是另一个支持内置运算符实现而不是宏的观点。

但是如何为 expression 参数做同样的事情 - 我不知道。你呢?

【讨论】:

  • 这比我想象的更有趣。谢谢! :-) (+1)
【解决方案2】:

宏由预处理器处理。运算符由编译器处理。

虽然sizeof(int) 可以很容易地被预处理器确定,但想想sizeof(MyCustomStruct)。为了评估它,我们必须知道 MyCustomStruct 的结构,它只由编译器评估。

编译时间相对于运行时间的优势当然是性能。如果编译时可以做一次,为什么要在运行时做很多次?

【讨论】:

  • 嗯,这并不完全准确。实际上,标准库有offsetof这样的宏。该宏的功能与类型参数的sizeof 没有太大区别。而offsetof 通常被实现为真正的宏(这方面有很多主题)。而且,就像sizeof 一样,它会生成一个编译时间常数。 sizeof 的至少部分功能可以以完全相同的方式实现(见我的回答)。
【解决方案3】:

其他运算符始终作为运行时执行。

这不是真的;常量表达式中的运算符在编译时计算。例如,15 * 60 是编译时评估的。 sizeof 运算符表达式,除了 C99 中引入的 VLA,根据定义都是常量,因此始终在编译时进行评估。

【讨论】:

  • VLA 上的 sizeof 除外
最近更新 更多