一般问题:在 C/C++ 中作为指针传递什么?

发布于 2024-11-06 15:24:21 字数 115 浏览 0 评论 0原文

嘿, 我想知道是否值得通过指针传递原始单值,例如 int、float、double 或 char?可能不值得吧!?但是,如果您只是通过指针传递所有内容,这是否会使程序变慢? 你应该总是只将数组作为指针传递吗? 谢谢!

Hey there,
I wonder if it's worth passing primitive single values like int, float, double or char by pointer? Probably it's not worth!? But if you would simply pass everything by pointer, is this making the program slower?
Should you always just pass arrays as pointer?
Thanks!

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

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

发布评论

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

评论(8

七七 2024-11-13 15:24:21

我想知道是否值得通过指针传递原始单值,如 int、float、double 或 char?

你想实现什么目标?您希望能够写入传入的值吗?或者您只需要使用它?如果你想写入它,惯用的方法是通过引用传递。如果您不需要写入它,则最好避免意外写入并按值传递的任何风险。按值传递将制作变量的副本以供本地使用。 (顺便说一句,如果您不想复制并想要一定程度的安全性,您可以通过 const 引用)

但是如果您只是通过指针传递所有内容,这会使程序变慢吗?

很难说。取决于很多事情。在按值传递和按引用(或指针)传递中,您都创建了新的原始类型。在按值传递中,您正在制作副本。在通过引用/指针传递时,您将一个地址传递给原始地址。然而,在后一种情况下,您需要额外获取可能会或可能不会被缓存的内存。如果不进行测量,很难说 100%。

话虽如此,我怀疑差异是否明显。编译器可能能够在许多按值传递的情况下优化副本,如 文章。 (感谢空间 C0wb0y)。

你应该总是将数组作为指针传递吗?

来自

在 C++ 中,不可能将完整的内存块作为参数传递给函数,但我们可以传递它的地址。

要传递数组:

 int foo(int bar[], unsigned int length)
 {
       // do stuff with bar but don't go past length
 }

我建议避免数组并使用 std::vector ,它具有更容易理解的复制语义。

I wonder if it's worth passing primitive single values like int, float, double or char by pointer?

What are you trying to accomplish? Do you want to be able to write to the passed in value? Or do you just need to use it? If you want to write to it, the idiomatic way is to pass by reference. If you don't need to write to it, you're best avoiding any risk that you'll write to it accidentally and pass by value. Pass by value will make a copy of the variable for local use. (as an aside, if you don't want to make a copy AND want some level of safety, you can pass by const reference)

But if you would simply pass everything by pointer, is this making the program slower?

Difficult to say. Depends on a lot of things. In both pass by value and pass by reference (or pointer) your making a new primitive type. In pass by value, you're making a copy. In pass by reference/pointer you're passing an address to the original. In the latter case, however, you're requiring an extra fetch of memory that may or may not be cached. Its very difficult to say 100% without measuring it.

That all being said, I doubt the difference is even noticeable. The compiler may be able to optimize out the copy in many pass-by-value cases, as indicated in this article. (thanks Space C0wb0y).

Should you always just pass arrays as pointer?

From this.

In C++ it is not possible to pass a complete block of memory by value as a parameter to a function, but we are allowed to pass its address.

To pass an array:

 int foo(int bar[], unsigned int length)
 {
       // do stuff with bar but don't go past length
 }

I'd recommended avoiding arrays and using std::vector which has more easily understood copy semantics.

合约呢 2024-11-13 15:24:21

如果您关心的是速度,那么通过指针传递原始值可能不值得——然后您就会有“间接”访问该值的开销。

然而,指针通常是“总线的宽度”,这意味着处理器可以一次发送整个值,而不是将值“移位”到总线上发送。因此,指针在总线上的传输速度可能比较小类型(如 char)更快。这就是为什么旧的 Cray 计算机过去将其 char 值设置为 32 位(当时总线的宽度)。

It's probably not worth passing primitive values by pointer if your concern is speed -- you then have the overhead of the "indirection" to access the value.

However, pointers often are the "width of the bus", meaning the processor can send the whole value at once, and not "shift" values to send-down-the-bus. So, it is possible pointers are transferred on the bus faster than smaller types (like char). That's why the old Cray computers used to make their char values 32 bits (the width of the bus at that time).

疯狂的代价 2024-11-13 15:24:21

处理大型对象(例如类或数组)时,传递指针比将整个对象复制到堆栈上更快。例如,这适用于 OOP

When dealing with large objects (such as classes or arrays) passing pointer is faster than copying the whole object onto the stack. This applies to OOP for example

仙女山的月亮 2024-11-13 15:24:21

查看您最喜欢的 C++ 教科书,了解有关“输出参数”的讨论。


使用指针作为输出参数而不是引用的一些优点是:

  • 没有令人惊讶的行为,没有远距离操作,调用站点和调用者的语义都很清晰。

  • 与 C 的兼容性(您的问题标题表明这一点很重要)

  • 可由其他语言使用,从共享库或 DLL 导出的函数不应使用仅限 C++ 的功能,例如引用。

Look in your favorite C++ textbook for a discussion of "output parameters".


Some advantages of using a pointer for output parameters instead of a reference are:

  • No surprising behavior, no action at a distance, the semantics are clear at the call site as well as the caller.

  • Compatibility with C (which your question title suggests is important)

  • Usable by other languages, functions exported from a shared library or DLL should not use C++-only features such as references.

ゃ人海孤独症 2024-11-13 15:24:21

您应该很少需要通过指针传递任何内容。如果需要修改参数的值,或者想要防止复制,请按引用传递,否则按值传递。

请注意,防止复制也可以通过复制省略来完成,因此您必须非常小心,不要陷入过早优化的陷阱。这实际上会使您的代码变慢。

You should rarely have to pass anything by pointer. If you need to modify the value of the parameter, or want to prevent a copy, pass by reference, otherwise pass by value.

Note that preventing a copy can also be done by copy-elision, so you have to be very careful not to fall into the trap of premature optimization. This can actually make your code slower.

我很OK 2024-11-13 15:24:21

除了我倾向于牢记的几条规则之外,您的问题没有真正的答案:
char 是 8 个字节,指针是 4 个字节,因此切勿将单个 char 作为指针传递。
像 int 和 float 这样的东西与指针大小相同,但必须引用指针,因此

如果我们使用 pentium i386 汇编器,技术上需要更多时间:

将值加载到 C 中参数“a”的寄存器中,其中是一个 int:

movl 8(%ebp),%eax  

相同的东西,但作为指针传递:

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

必须取消引用指针需要另一个内存操作,因此理论上(不确定是否在现实生活中)传递指针更长......
之后就是内存问题。如果你想有效地编码所有组合类型(类、结构、数组...)都必须通过指针传递。
想象一下,执行一个类型为 16 字节的递归函数,该函数通过副本传递 1000 次调用,从而在堆栈中生成 16000 字节(您并不真正想要这样,对吗?:))

因此,为了使其简短明了:请看您的类型的大小,如果它比指针大,则通过指针传递它,否则通过副本传递它...

There's is no real answer to your question except few rules that I tend to bare in mind:
char is 8 bytes and a pointer is 4 bytes so never pass a single char as a pointer.
after things like int and float are the same size as a pointer but a pointer has to be referenced so that technically takes more time

if we go to the pentium i386 assembler:

loading the value in a register of a parameter "a" in C which is an int:

movl 8(%ebp),%eax  

the same thing but passed as a pointer:

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

Having to dereference the pointer takes another memory operation so theorically (not sure it is in real life) passing pointers is longer...
After there's the memory issue. If you want to code effectively everything composed type (class,structure,arrays...) has to be passed by pointer.
Just imagine doing a recursive function with a type of 16bytes that is passed by copy for 1000 calls that makes 16000 bytes in the stack (you don't really want that do you ? :) )

So to make it short and clear: Look at the size of your type if it's bigger than a pointer pass it by pointer else pass it by copy...

触ぅ动初心 2024-11-13 15:24:21

按值传递基本类型,并将对象作为 const 引用传递。尽可能避免使用指针。取消引用指针会产生一些开销,并且会使代码变得混乱。比较下面的 factorial 函数的两个版本:

// which version of factorial is shorter and easy to use?

int factorial_1 (int* number)
{
  if ((*number) <= 1)
    return 1;
  int tmp = (*number) - 1;
  return (*number) * factorial_1 (&tmp);
}

// Usage:
int r = 10;
factorial_1 (&r); // => 3628800


int factorial_2 (int number)
{
  return (number <= 1) ? 1 : (number * factorial_2 (number - 1));
}

// Usage:
// No need for the temporary variable to hold the argument.
factorial_1 (10); // => 3628800

调试变得很困难,因为您无法确定对象的值何时何地可能发生变化:

int a = 10;
// f cound modify a, you cannot guarantee g that a is still 10.
f (&a); 
g (&a);

优先使用 vector 类而不是数组。它可以根据需要增大和缩小,并跟踪其大小。访问 vector 元素的方式与数组兼容:

int add_all (const std::vector<int>& vec)
{
    size_t sz = vec.size ();
    int sum = 0;
    for (size_t i = 0; i < sz; ++i)
        sum += vec[i]; 
}

Pass primitive types by value and objects as const references. Avoid pointers as much as you can. Dereferencing pointers have some overhead and it clutters code. Compare the two versions of the factorial function below:

// which version of factorial is shorter and easy to use?

int factorial_1 (int* number)
{
  if ((*number) <= 1)
    return 1;
  int tmp = (*number) - 1;
  return (*number) * factorial_1 (&tmp);
}

// Usage:
int r = 10;
factorial_1 (&r); // => 3628800


int factorial_2 (int number)
{
  return (number <= 1) ? 1 : (number * factorial_2 (number - 1));
}

// Usage:
// No need for the temporary variable to hold the argument.
factorial_1 (10); // => 3628800

Debugging becomes hard, as you cannot say when and where the value of an object could change:

int a = 10;
// f cound modify a, you cannot guarantee g that a is still 10.
f (&a); 
g (&a);

Prefer the vector class over arrays. It can grow and shrink as needed and keeps track of its size. The way vector elements are accessed is compatible with arrays:

int add_all (const std::vector<int>& vec)
{
    size_t sz = vec.size ();
    int sum = 0;
    for (size_t i = 0; i < sz; ++i)
        sum += vec[i]; 
}
灼疼热情 2024-11-13 15:24:21

,唯一传递非常量引用的情况是函数需要输出参数。

NO, the only time you'd pass a non-const reference is if the function requires an output parameter.

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