mtr*_*eur 3 c language-lawyer constant-expression constantfolding
我很好奇是否有关于在C中进行恒定折叠的任何保证.
在我不知道其声誉的网站上的这个链接发表了一个随意的评论:
所有C编译器都可以折叠宏扩展后存在的整数常量表达式(ANSI C要求).
但我没有看到任何内容,例如C编程语言,第二版(我认为已经彻底更新以解释ANSI C的所有细节).但是在检查了相关单词的引用索引后,我发现没有任何承诺.第38页和第209页特别接近,因为他们说任何可以在编译时评估的表达式都可以用于可以使用常量的地方(如果我们足够迂腐,可能有一些限制),并且它表示这样的表达式" 可能 "在编译时进行评估,而不是"将"/(某些同义词).
我搜索了这个C89最终草案.单词"折叠"和"折叠"没有产生任何有价值的结果,搜索"常量表达"产生了63个匹配,其中我检查了大约一半.感兴趣的主要部分似乎基本上与书相同(它使用" can "而不是"may",但在这种情况下它们是同义词).
这两个似乎在逻辑上强烈暗示我每个ANSI C编译器必须具有基本的常量折叠功能,但同时,似乎没有任何硬性禁止将常量表达式编译成计算表达式的代码在运行时(这样的实现仍然受益于常量表达式,因为编译器可以生成一次计算它的代码然后假设值不会改变,并且这样的实现可能会受到给定底层架构中的限制的强制 - 例如几个RISC架构必须使用两条指令来初始化某些可能的值,或者从内存位置加载它们.
我还简要搜索了这个C99最终草案,但是"折叠"产生了一个没有价值的结果,而"折叠"和"常数"有超过一百个匹配,我目前无法分配时间来爬行.
我在一些比特杂乱的代码中编写了这些宏以获得更多的语义/意图清晰度:
#define UCHAR_LOW_N_BITS_m(n) (unsigned char )(UCHAR_MAX >> (CHAR_BIT - (n)))
#define UCHAR_NTH_BIT_m(n) (unsigned char )(1 << (n))
Run Code Online (Sandbox Code Playgroud)
..where n总是一个整数字面值.我想要得到安慰,听到一个令人安心的声音说"没关系,所使用的每个C编译器远程重要都会为你折叠这些常量".(PS我问了一个单独的问题,是否UCHAR_NTH_BIT_m应该表现为从第0位或第1位开始,希望是在正确的位置.)
是的,底部的一个可以变成单独的宏,例如#define UCHAR_1ST_BIT_m (unsigned char )1通过#define UCHAR_3RD_BIT_m (unsigned char )4或者我在代码中碰巧需要的许多宏- 虽然我还没有决定哪个更好,但这可能是一个没有实际意义的点,因为如果我想要的话要成为一名优秀的迂腐语言 - 律师型C程序员,我无法完全避开顶级程序员(必须确保代码在那些DSP /嵌入式和古代大型机C实现上做正确的事情).
通常,C 标准不指定如何编译某些内容。你永远无法保证一种实现方式比另一种更快。不能保证一定发生常量折叠,但由于编译器必须能够在编译时评估常量表达式(以处理#if指令和数组声明符),因此编译器很可能会进行常量折叠。毕竟,能够进行不断折叠但又不这样做是没有意义的。
在C标准中,编译时的术语是转换时间,在编译时发生的事件可以描述为在转换期间.您可以搜索这些条款的标准.
本标准中与您的主题最接近的是6.6节(C11)中常量表达式的定义.概述是:
可以在转换期间而不是运行时期间评估常量表达式,并且因此可以在常量可以在任何地方使用.
请注意,"可以"并不意味着"必须".我们期望一个高质量的编译器在编译时评估常量表达式,尽管这不是绝对的要求.
第6.6节太大了,无法在此处粘贴整个内容,但是通过查阅C标准(或者诸如N1570之类的草案),您可以了解哪些表达式被定义为常量表达式,并且假设您的编译器在编译时间.
如果n >= 0 && n < CHAR_BIT * sizeof(int) - 1和n是一个整型常量表达式,则(unsigned char )(1 << (n))是一个整型常量表达式,因为:它的操作数是整数常量,它不使用常量表达式中禁止的运算符之一(例如++),并且允许强制转换因为它强制转换从整数类型到另一个整数类型.
如果n超出此范围,则表达式不是常量表达式,并导致未定义的行为.
你的另一个表达是相似的; 只要CHAR_BIT - n落在相同的有效范围内,它就是ICE .
| 归档时间: |
|
| 查看次数: |
162 次 |
| 最近记录: |