Chr*_*utz 11 c standards simplification memory-address
第§6.5.3.2节"地址和间接操作符"3表示(仅限相关部分):
一元&运算符返回其操作数的地址....如果操作数是一元运算
*
符的结果,则不会对该运算符和&
运算符进行求值,结果就好像两者都被省略,除了对运算符的约束仍然适用且结果不是左值.类似地,如果操作数是[]
运算符的结果,&
则不会对运算符或*
由其暗示的一元[]
进行求值,结果就像&
删除了[]
运算符并将运算符更改为+
运算符一样....
这意味着:
#define NUM 10
int tmp[NUM];
int *i = tmp;
printf("%ti\n", (ptrdiff_t) (&*i - i) );
printf("%ti\n", (ptrdiff_t) (&i[NUM] - i) );
Run Code Online (Sandbox Code Playgroud)
应该完全合法,打印0和NUM
(10).标准似乎非常清楚,这两种情况都需要进行优化.
但是,它似乎不需要优化以下内容:
struct { int a; short b; } tmp, *s = tmp;
printf("%ti\n", (ptrdiff_t) (&s->b - s) );
Run Code Online (Sandbox Code Playgroud)
这似乎非常不一致.我没有理由认为上面的代码不应该打印sizeof(int)
加号(不太可能)填充(可能是4).
简化&->
表达式在概念上(IMHO)将是&[]
一个简单的地址加偏移量.它甚至是一个在编译时可以确定的偏移量,而不是[]
运算符可能的运行时间.
关于为什么这么看似不一致的理由是否存在?
在你的例子中,&i[10]
实际上是不合法的:它变成了i + 10
,它变成了NULL + 10
,并且你不能对空指针执行算术。(6.5.6/8列出了可以进行指针运算的条件)
无论如何,这条规则是在C99中添加的;它在 C89 中不存在。我的理解是,它的添加很大程度上是为了使代码像下面这样定义良好:
int* begin, * end;
int v[10];
begin = &v[0];
end = &v[10];
Run Code Online (Sandbox Code Playgroud)
最后一行在 C89(和 C++)中技术上是无效的,但由于这条规则而在 C99 中是允许的。这是一个相对较小的变化,使常用的结构有了明确的定义。
因为您无法对空指针执行算术,所以您的示例 ( &s->b
) 无论如何都是无效的。
至于为什么会出现这种“不一致”,我只能猜测。很可能没有人想到要使其保持一致,或者没有人看到一个令人信服的用例。这可能是经过考虑并最终被拒绝的。没有关于&*
减少理由的评论。您也许可以在WG14 论文中找到一些明确的信息,但不幸的是,它们的组织似乎相当糟糕,因此搜索它们可能会很乏味。