GCC 和 Clang 都支持(作为扩展)0 大小(也称为“0 长度”)数组。
0 大小数组的原理是什么(示例int x[0]
)?
GCC 和 Clang 都支持(作为扩展)0 大小(也称为“0 长度”)数组。
0 大小数组的原理是什么(示例int x[0]
)?
n3301,6.6常量表达式,p4(重点添加):
每个常量表达式的计算结果应为其类型可表示值范围内的常量。
n3301,6.5.15逻辑或运算符,p4(强调添加):
如果第一个操作数比较不等于 0,则不评估第二个操作数。
问题:为什么第一个要求不依赖于这种常量表达式的评估(或非评估)的要求?
换句话说:为什么“每个常量表达式应计算为......”而不是“每个计算的常量表达式应计算为......”?
这是一个疏忽吗?
问题的原因:有些人认为“每个常量表达式应计算为……”优先于“第二个操作数不被计算”。
是的,n3301有脚注119:
- 因此,在下面的初始化中,
static int i = 2 || 1 / 0;
该表达式是有效的整数常量表达式,其值为 1。
然而,“在ISO标准中,注释无一例外都是非规范性的。 ”
如果有[[noreturn]]
(C2X,n3301),那么为什么没有[[always_return]]
?
的语义[[always_return]]
可能如下:
使用属性声明的函数
[[always_return]]
应始终返回其调用者。
其基本原理[[always_return]]
是提示编译器进行优化。
示例(取自N3128):
extern void g(int x);
int f(int a, int b)
{
g(b ? 42 : 43);
return a / b;
}
编译器可以自由地(乐观地)假设 UB 不会发生。
但是,UB 的任何(危险)后果只有当 UB 发生时(即在抽象机器级别的执行中出现)才会发生。
在此示例中g
可能会终止程序(即不返回)。因此,据我了解,编译器可能不会折叠b ? 42 : 43
到 42,因为在抽象机器级别a / b
可能不会执行,因此编译器可能不会b
传播/使用非零的假设。
但是,如果g
用声明[[always_return]]
,那么据我所知,编译器可能会折叠b ? 42 : 43
到 42,因为在抽象机器级别a / b
总是执行,因此编译器可能会b
传播/使用非零的假设。
PS 同样的问题也存在[[may_return]]
。
UPD。为了折叠b ? 42 : 43
到 42,g
不仅需要始终返回,还需要没有可观察的行为 (OB)。这是因为在 C 中,OB 必须在 UB 之前发生。因此,可能需要更多属性:[[observable]]
,[[noobservable]]
。并且g
可以声明为:
extern [[always_return]] [[noobservable]] void g(int x);
转换说明符是否s
指定了字符的书写方向/顺序?
N3220 工作草案,7.23.6p8(重点添加):
s 如果不存在 l 长度修饰符,则参数应为指向字符类型存储的指针。326)存储中的字符将写入到(但不包括)终止空字符。如果指定了精度,则写入的字节数不会超过该值。如果未指定精度或精度大于存储的大小,则存储应包含一个空字符。
这是否意味着以下程序:
#include <stdio.h>
int main(void)
{
char s[] = {'x', '\0', 'y'};
printf("%s", s);
}
可以打印吗y
?
尽管书写方向/顺序可能很明显,但它是否具体说明?
为什么会-LLONG_MIN
导致未定义的行为?
C11,6.5.3.3p3:
一元 - 运算符的结果是其(提升的)操作数的负数。对操作数执行整数提升,结果具有提升后的类型。
这里我们看到C标准并不要求实现一元-运算符,例如使用按位-不后跟加1,其中“加1”可能会导致未定义的行为。
如何从导致未定义行为的引用文本中推断出来-LLONG_MIN
?