c - sizeof的实现 - sizeof编译时确定




是在编译时还是在运行时评估常量C表达式? (6)

每次使用TIMERB_100_MS宏时,操作32768/10都会在运行时发生吗?

代码中使用TIMERB_100_MS每个位置,预处理器将替换为TIMERB_100_MS

该表达式是否得到进一步优化(它的计算结果为常量)取决于编译器。

如果我编写一个使用其他预处理器常量执行操作的#define ,那么每次宏在运行时出现时是否计算出最终值? 这取决于编译器中的优化,还是属于标准?

例:

#define EXTERNAL_CLOCK_FREQUENCY    32768
#define TIMER_1_S                   EXTERNAL_CLOCK_FREQUENCY
#define TIMER_100_MS                TIMERB_1_S / 10

每次使用TIMER_100_MS宏时,操作32768/10都会在运行时发生吗?

我想避免以下情况:

#define EXTERNAL_CLOCK_FREQUENCY    32768
#define TIMER_1_S                   EXTERNAL_CLOCK_FREQUENCY
#define TIMER_100_MS                3276

概要

编译器需要能够计算常量积分表达式,因为它们是在编译时计算数组大小等内容所必需的。 但是,标准只说他们“可以” - 而不是“必须” - 这样做。 因此,只有脑死亡的编译器才会在编译时评估常量积分表达式,但是对非常规编译器的汇编输出的简单检查将验证每种情况。


伙计们,这种转变被称为“不断折叠”,甚至大多数学生编制者也会这样做。 只要你有一个由你或你的大学室友建立的编译器并且你正在编译一个静态类型的语言,即使没有打开优化,你也可以依靠它。 如果你正在处理一些允许改变/的意思的古怪动态语言,那就不一样了。


宏只是文本替换,因此在您的示例中,在程序中编写TIMER_100_MS是编写TIMER_100_MS一种奇特方式。

因此,问题是编译器何时评估32768 / 10 ,这是一个常量积分表达式。 我不认为标准在这里需要任何特定的行为(因为运行时和编译时评估在效果上是无法区分的),但任何中途正常的编译器都会在编译时对其进行评估。


我不知道有任何标准可以保证它会被优化。 预处理器将替换32768/10替换TIMER_100_MS,您可以通过运行gcc -c看到它。 要查看编​​译器是否进一步优化,请运行gcc -S并检查汇编程序。 使用gcc 4.1,即使没有任何优化标志,这也会在编译期间减少到常量:

#include <stdlib.h>
#include <stdio.h>

#define EXTERNAL_CLOCK_FREQUENCY    32768
#define TIMER_1_S                   EXTERNAL_CLOCK_FREQUENCY
#define TIMER_100_MS                TIMER_1_S / 10

int main(int argc, char **argv)
{
  printf("%d\n", TIMER_100_MS);

  return(0);
}

gcc -S test.c
cat test.s

...
    popl    %ebx
    movl    $3276, 4(%esp)
    leal    LC0-"L00000000001$pb"(%ebx), %eax
    movl    %eax, (%esp)
    call    L_printf$stub
...

编译器应优化该表达式。 我不认为这是标准所要求的,但我从未见过不会执行该任务的编译器。

但是,你不应该写:

#define TIMER_100_MS      TIMERB_1_S / 10

...因为这是一个等待发生的错误。 你应该总是将涉及表达式的#defines括起来。

#define TIMER_100_MS      (TIMERB_1_S / 10)

考虑:

i = 10 * TIMER_100_MS;

第一种情况是32768((10 * TIMERB_1_S)/ 10),第二种情况是32760(10 *(TIMERB_1_S / 10))。 这里不是一个关键的区别,但你必须意识到它!


这是不正确的,编译器无法在编译时操作浮点数。 如果您在编译时对3276值感到满意,那么您可以继续使用,但编译器无法在编译时使用浮点精度来评估此值。 浮点数对于编译器来说太难以优化,因为优化浮点数会导致数学表达式出现意外结果,因此一个不错的编译器(任何gcc版本,任何clang版本,任何msvc版本,任何icc版本)都不会将其简化为3276.8,故事结束。

问题的另一部分,你问过它是否会针对每次宏扩展进行评估。 再次,如果您对3276值很好,那么答案是否定的,它取决于编译器,优化级别和背景,它可以放在常量表中,也可以在代码中内联。 永远不会为每个宏扩展在运行时计算相同的表达式。 同样,如果您希望浮点精度得到3276.8,那么将在运行时为每个宏扩展计算该表达式。

请查看更多编译和优化方面: http://www.agner.org/optimize/#manualshttp://www.agner.org/optimize/#manuals





c-preprocessor