在C语言中,使用&;和[]一起快速获取指向数组中对象的指针?

在C语言中,使用&;和[]一起快速获取指向数组中对象的指针?,c,performance,C,Performance,我知道这可以用来获取索引(并自动执行指针算法): struct Obj*c=&p[i] 但是,与手动执行指针运算相比,这是否会对性能造成影响 struct Obj*c=p+i 有什么理由应该避免使用第一个版本吗?第二个版本令人困惑,是一个异常现象,所以除非你有非常令人信服的理由使用它,否则不要使用。如果你这样做了,那么你应该记录为什么有人不去用前者代替它 第二种形式也很脆弱,因为如果通过重构和引入新结构(如: struct Mobj *c = p + i * sizeof(struct Obj)

我知道这可以用来获取索引(并自动执行指针算法):

struct Obj*c=&p[i]

但是,与手动执行指针运算相比,这是否会对性能造成影响

struct Obj*c=p+i


有什么理由应该避免使用第一个版本吗?

第二个版本令人困惑,是一个异常现象,所以除非你有非常令人信服的理由使用它,否则不要使用。如果你这样做了,那么你应该记录为什么有人不去用前者代替它

第二种形式也很脆弱,因为如果通过重构和引入新结构(如:

struct Mobj *c = p + i * sizeof(struct Obj);
你忘了更新
sizeof
部件,现在你的代码被彻底破坏了

这当然忽略了这样一个事实,即在进行指针数学运算时,它将自动增加结构的大小,即:

p[i] == *(p + i)
但在你的情况下,你所做的实际上是:

p[i * sizeof(Obj)]
这不是你想要的


少就是多。编码已经够难了,不要把事情复杂化。

是的,没关系。事实上,从编译器的角度来看,使用p实际上与&p[0]相同。始终让编译器为您计算指针,使用第一种形式。

C标准规定
&array[index]
数组+索引
完全等效。这意味着两者都执行指针算法,因此它们应该没有什么不同

即使它们是不同的,选择其中一个将是一个微优化,这是不值得做的,除非你在它们之间有一个显著的可测量的差异

但是,与手动执行指针运算相比,这是否会对性能造成影响

使用索引运算符的表达式被定义为等价于涉及指针算术和解引用的相应操作,因此

&p[i]
完全等同于

&(*(p + i))
p + i
该标准进一步规定,当
&
运算符的操作数是
*
运算符的结果时,两个运算符都不求值,并且结果就像两个运算符都被省略一样,因此这反过来相当于

&(*(p + i))
p + i
,它定义了行为,只要它不打算在从中派生指针
p
的数组开始之前生成指向的指针,也不超过其结束后的一个位置

虽然可以想象编译器在一种情况下会产生与另一种情况不同或更糟糕的代码,但没有理由期望这样

有什么理由可以避免第一种情况吗


不多。后者的认知负荷较轻,更容易阅读,因为(从语法上)它只涉及一个操作而不是两个操作。出于这个原因,我倾向于自己喜欢它。另一方面,理解它可能不那么直观。

在任何一个好的编译器上,不是真的。我认为一个好的编译器应该生成同样有效的代码。第二个应该是
struct Obj*c=p+I与第一个问题完全相同。好吧,编辑后的问题很简单。C标准定义了两个等价的表达式。此外,对于任何指针或数组
p
和索引
i
,表达式
p[i]
完全等于
*(p+i)
。这是C标准的一部分。感谢您澄清@tadman。我不知道指针运算会考虑大小(虽然它不是我原来的问题的意图)。我认为标准中有一个特殊的规则:<代码>和*p>代码>完全等同于<代码> p>代码>。同样的规则适用于<代码> []/COD>符号。因此,&*E相当于E(即使E是空指针),并且&(E1[E2])相当于((E1)+(E2))-因此没有任何区别。@EugeneSh.,它被明确允许通过指针加法计算指向数组最后一个元素后一个元素的指针,并且还明确指定尝试取消引用这样的结果会产生UB。请参阅标准的段落。@user3386109,您是正确的,我已相应地更新了此答案。“事实上,我怀疑这条特殊规则正是为这个案子而制定的。”尤金内什。是的,
*(p+i)
正在解引用,并且我指定在
i
小于数组元素的数量时,以下内容的等价性是临时的。然而,正如用户3386109所观察到的,还有一个明确的特殊规定,即当
&
应用于
*
运算符的结果时,两个运算符都不进行评估,就好像两个运算符都被省略了一样。这是我的标准。@ BenVoigt,这就是我想回答的问题。”RICKROVE:约翰现在在他的回答中正确地捕捉到所有细微差别,IMO.,我也看到C标准在哪里(冗余地)使DBUE谈论的话,所以我之前的评论是错误的。