常量指针数组还是指向数组的指针? C语言中什么更快?

发布于 2024-10-14 05:38:57 字数 633 浏览 1 评论 0原文

你好,我现在正在上 C 中级课程,这个想法刚刚出现在我的脑海中:

int multi[3][4]; // const multidimensional array

int* ptr = *multi; // ptr is a pointer variable that hold the address of multi const array

那么,访问多维数组位置更快/更小/优化的方法是什么?

这个:

multi[3][1]; // index the value position

*(*(multi+2)+1); // pointer to the position on the array

或(更新)

ptr += 9; // pointer arithmetic using auxiliary pointer

由于“multi”是一个常量数组,编译器应该“知道”元素位置的本地化,以防使用指向该数组的变量指针,这可能需要更多的处理时间,另一方面搜索我想要显示的项目时,手可能会更快。更快/更小/优化的方法是什么?

先感谢您。

Hello I'm in an intermediary C class right now and this thought just came to my mind:

int multi[3][4]; // const multidimensional array

int* ptr = *multi; // ptr is a pointer variable that hold the address of multi const array

So, what is faster/smaller/optimized for access a multidimensional array position?

This:

multi[3][1]; // index the value position

or

*(*(multi+2)+1); // pointer to the position on the array

or (UPDATED)

ptr += 9; // pointer arithmetic using auxiliary pointer

Since "multi" is an const array the compiler should "know" already the localization of the element position, in case of using an variable pointer pointing to that array that could take more processing time, on the other hand could be faster when searching for the item that I want to display. What is the faster/smaller/optimized approach?

Thank you in advance.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

倾城花音 2024-10-21 05:38:57

它们都以相同的方式编译,*(pointer_to_first_element + x + y)

They're all compiled in the same way, *(pointer_to_first_element + x + y).

愿与i 2024-10-21 05:38:57

首先

int multi[3][4];

不是 const 数组。该声明中没有任何 const 内容。

其次,

int* ptr = *multi;

将使ptr指向元素multi[0][0]。数值上它与multi[0]的地址和整个multi的地址相同,但类型不同。

第三,

multi[3][1];

根据定义,与 相同

*(*(multi + 3) + 1);

,因此性能上不存在合理的差异。它与上面所说的有何联系尚不清楚。

第四,

*ptr + 9;

其中没有任何“指针算术”。它相当于

multi[0][0] + 9;

普通的积分加法。同样,它与上面所说的内容有何联系尚不清楚。

最后,您的问题的标题为“常量指针数组或指向数组的指针”,而在问题的实际文本中我两者都没有看到。

Firstly

int multi[3][4];

is not a const array. There is nothing const in this declaration.

Secondly,

int* ptr = *multi;

will make ptr point to the element multi[0][0]. Numerically it is the same as the address of multi[0] and the address of the entire multi, but the types are different.

Thirdly,

multi[3][1];

is by definition the same as

*(*(multi + 3) + 1);

so there can be no justified difference in performance. How it is connected to what was said above is not clear.

Fourthly,

*ptr + 9;

has no "pointer arithmetic" in it whatsoever. It is equivalent to

multi[0][0] + 9;

which is an ordinary integral addition. Again, how it is connected to what was said above is not clear.

Finally, your question is titled as "Constant pointer array or pointer to an array", while in the actual text of the question I see neither.

甜点 2024-10-21 05:38:57

如果你的代码被抛弃,那么无论你的代码有多快都没有关系,因为没有人能够理解和维护它;此外,棘手的代码有时会阻止编译器进行更好的优化。

例如:

int main(void)
{
  int arr[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
  int *p = *arr; // == arr[0] == &arr[0][0]

  int x;

  x = arr[2][3];         // Straightforward array access
  x = *(*(arr+2)+3);     // Ugly pointer arithmetic
  x = *(ptr + 11);       // Slightly less ugly pointer arithmetic

  return 0;
}

我通过 gcc -c -g -Wa,-a,-ad > 运行了上面的内容foo.lst 以交错生成生成的程序集和源代码。

这是 x = arr[2][3]; 的翻译:

movl      -16(%ebp), %eax     
movl      %eax, -8(%ebp)      

这是 x = *(*(arr+2)+3); 的翻译:

leal      -60(%ebp), %eax
addl      $44, %eax
movl      (%eax), %eax
movl      %eax, -8(%ebp)

最后,x = *(ptr + 11); 的翻译:

movl      -12(%ebp), %eax
addl      $44, %eax
movl      (%eax), %eax
movl      %eax, -8(%ebp)

不要试图超越你的编译器。现在已经不是 20 世纪 70 年代了。 gcc 知道如何有效地进行数组访问,而无需您告诉它。

您甚至不应该考虑此级别的性能除非您已经调整了算法和数据结构,在编译器上使用了最高的优化设置(FWIW,-O1 为所有三个版本生成相同的代码),并且您仍然无法满足硬性能要求(在这种情况下,正确的答案通常是购买更快的硬件)。在没有首先通过分析器运行代码以找到真正的瓶颈之前,您不应该更改任何内容测量,不要猜测。

编辑

当然,当文字 23 被变量替换时,情况就会发生变化。在这种情况下,*(ptr + offset); 看起来效果最好。但幅度不大。我仍然认为在这个层面上清晰度更重要。

It doesn't matter how fast your code is if it gets tossed because nobody else can understand and maintain it; also, tricky code can sometimes prevent your compiler from making a better optimization.

For example:

int main(void)
{
  int arr[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
  int *p = *arr; // == arr[0] == &arr[0][0]

  int x;

  x = arr[2][3];         // Straightforward array access
  x = *(*(arr+2)+3);     // Ugly pointer arithmetic
  x = *(ptr + 11);       // Slightly less ugly pointer arithmetic

  return 0;
}

I ran the above through gcc -c -g -Wa,-a,-ad > foo.lst to get the generated assembly and source code interleaved.

Here's the translation for x = arr[2][3];:

movl      -16(%ebp), %eax     
movl      %eax, -8(%ebp)      

Here's the translation for x = *(*(arr+2)+3);:

leal      -60(%ebp), %eax
addl      $44, %eax
movl      (%eax), %eax
movl      %eax, -8(%ebp)

And finally, the translation for x = *(ptr + 11);:

movl      -12(%ebp), %eax
addl      $44, %eax
movl      (%eax), %eax
movl      %eax, -8(%ebp)

Don't try to outsmart your compiler. This isn't the 1970s anymore. gcc knows how to do array accesses efficiently without you having to tell it.

You shouldn't even be thinking about performance at this level unless you've tuned your algorithm and data structures, used the highest optimization settings on your compiler (FWIW, -O1 generates the same code for all three versions), and you're still failing to meet a hard performance requirement (in which case, the right answer is usually to buy faster hardware). And you shouldn't change anything without first running your code through a profiler to find the real bottlenecks. Measure, don't guess.

EDIT

Naturally, when the literals 2 and 3 are replaced by variables, the situation changes. In that case, the *(ptr + offset); comes out looking the best. But not by much. And I'll still argue that clarity matters more at this level.

青萝楚歌 2024-10-21 05:38:57

a[i] 表示 *(a+i),其实也可以写i[a]你的编译器会接受它。

无论如何,理论上,*(ptr+i) 可能比 ptr[j][k] 稍快一些,因为您正在执行一次加法(而 ptr [j][k] 可能需要 2)。

a[i] means *(a+i), in fact you can also write i[a] and your compiler will accept it.

*(ptr+i) anyway could be slightly faster than ptr[j][k] in theory, since you're doing a single addition (while ptr[j][k] could require 2).

下壹個目標 2024-10-21 05:38:57

我不确定 const 数组来自哪里,但为了讨论,我们假设原始帖子中有一些。

由于原始发布者没有明确提及 PC 编程,const 数组和常规数组不一定以相同的方式编译。

在嵌入式系统中,如果 const 数组分配在真正的非易失性存储器(即具有真正 ROM 的嵌入式应用程序)中,则 const 数组可能比非 const 数组慢。速度慢与 ROM 的访问时间有关,并且与硬件高度相关。


关于指针运算,这是访问数组的唯一方法。 C语言中的数组语法就是编译器人所说的“语法糖”,即只是为了看起来而已。 这样的数组访问

像arr[i]

被编译器翻译为

*(arr+i)

,它们在性能和功能上是等效的。

I'm not sure where the const arrays came from, but for the discussion, lets assume there were some in the original post.

As the original poster didn't explicitly mention PC programming, const arrays and regular arrays are not necessarily compiled in the same way.

In embedded systems, const arrays may be slower than non-const ones, if the const arrays are allocated in true non-volatile memory, ie an embedded application with real ROM. The slowness is related to access times of the ROM, and highly hardware-specific.


Regarding pointer arithmetic, that is the only way to access arrays. The array syntax in the C language is what the compiler people call "syntactic sugar", i.e it is just there for looks. An array access like

arr[i]

is translated by the compiler to

*(arr+i)

and they are equivalent in performance and function.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文