【问题标题】:Variable Length Array Performance Implications (C/C++)可变长度数组性能影响 (C/C++)
【发布时间】:2013-09-27 03:38:35
【问题描述】:

我正在编写一个相当简单的函数,将数组发送到文件描述符。但是,为了发送数据,我需要附加一个一字节的标头。

这是我正在做的事情的简化版本,它似乎有效:

void SendData(uint8_t* buffer, size_t length) {
  uint8_t buffer_to_send[length + 1];
  buffer_to_send[0] = MY_SPECIAL_BYTE;
  memcpy(buffer_to_send + 1, buffer, length);
  // more code to send the buffer_to_send goes here...
}

就像我说的,代码似乎运行良好,但是,我最近养成了使用 Google C++ 样式指南的习惯,因为我当前的项目没有为它设置样式指南(实际上我是唯一的软件我项目的工程师,我想使用工业中使用的东西)。我运行了 Google 的 cpplint.py,它抓住了我正在创建 buffer_to_send 的行,并提出了一些关于不使用可变长度数组的评论。具体来说,以下是 Google 的 C++ 风格指南对可变长度数组的看法……

http://google-styleguide.googlecode.com/svn/trunk/cppguide.xml#Variable-Length_Arrays_and_alloca__

根据他们的 cmets,我似乎可能找到了我的代码中看似随机崩溃的根本原因(这种情况很少发生,但仍然很烦人)。但是,我对如何解决它感到有些不安。

这是我提出的解决方案:

  1. 使 buffer_to_send 本质上是一个固定长度的固定长度数组。我在这里能想到的问题是我必须使缓冲区与我想要发送的理论上最大的缓冲区一样大。在一般情况下,缓冲区要小得多,每次调用函数时我都会浪费大约 0.5KB。请注意,程序必须在嵌入式系统上运行,虽然我不一定要计算每个字节,但我希望使用尽可能少的内存。

  2. 使用 new 和 delete 或 malloc/free 动态分配缓冲区。这里的问题是该函数被频繁调用,并且在不断向操作系统请求内存然后释放它方面会有一些开销。

  3. 使用两次连续调用 write() 将数据传递给文件描述符。也就是说,第一次写入将只传递一个字节,而下一次将发送缓冲区的其余部分。虽然看起来很简单,但我需要对代码进行更多研究(请注意,我从一位已经离开我工作的公司的以前的工程师那里得到了这个代码),以保证两个连续的写入是原子发生的。此外,如果这需要锁定,那么它实际上会变得更复杂,并且比案例 #2 对性能的影响更大。

请注意,我不能将 buffer_to_send 设为成员变量或将其限定在函数之外,因为在任何给定时间(可能)从不同线程多次调用该函数。

请让我知道您的意见以及我的首选方法应该是什么。感谢您的宝贵时间。

【问题讨论】:

  • 文件描述符后面是什么?多次写入调用的影响因目标而异。另外,你对长度有“硬”限制吗?
  • 我对长度的严格限制是巨大的,我不希望每次调用函数时都分配一堆不需要的内存。此外,文件描述符本质上是与串行设备的连接。
  • 你考虑过使用writev()吗?它旨在将多个缓冲区拼接为一个,使用相当于write() 与一个缓冲区。
  • 这是叶函数吗?如果是这样,您就不必担心避免大的堆栈分配。

标签: c++ c arrays


【解决方案1】:

您可以使用 writev() 将选项 3 中对 write() 的两个连续调用折叠成一个调用。

http://pubs.opengroup.org/onlinepubs/009696799/functions/writev.html

【讨论】:

  • 正是我需要的!感谢您向我介绍另一个我不知道存在的内置功能,但我(现在)绝对不能没有!
【解决方案2】:

我会选择选项 1。如果您知道数据的最大长度,则使用固定大小的数组在堆栈上分配那么多空间(加上一个字节)。这并不比您显示的可变长度数组差,因为您必须始终在堆栈上留有足够的空间,否则您根本无法处理最大长度(最坏的情况下,您的代码会在较大的缓冲区大小上随机崩溃)。在调用此函数时,没有其他东西会占用堆栈上的更多空间,因此分配固定大小的数组是安全的。

【讨论】:

  • 'int x[length+1]`是分配在栈上还是堆上?
  • @koodawg:像这样的可变长度数组分配在自动存储(堆栈)中。
猜你喜欢
  • 1970-01-01
  • 2014-06-17
  • 2013-06-23
  • 2021-07-11
  • 1970-01-01
  • 1970-01-01
  • 2012-12-14
  • 2014-03-27
  • 2018-12-16
相关资源
最近更新 更多