【问题标题】:C memory space and #definesC 内存空间和#defines
【发布时间】:2009-08-28 07:28:53
【问题描述】:

我正在研究嵌入式系统,所以内存对我来说很宝贵。

一个反复出现的问题是,我在尝试为其编译程序时内存空间不足。这通常通过限制可能占用大量空间的 typedef 的数量来解决。

有一个宏生成器,我用它来创建一个包含很多#define 的文件。 其中一些是简单的值,另一些是边界检查

#define SIGNAL1 (float)0.03f
#define SIGNAL1_ISVALID(value) ((value >= 0.0f) && (value <= 10.0f))

现在,我不使用所有这些定义。我使用了一些,但实际上不是大多数。 有人告诉我,如果不使用它们,它们实际上不会占用任何内存,但我不确定这一点。我希望通过删除未使用的内存来释放一些额外的内存(但我再次被告知这是没有意义的)。

未使用的#define 是否占用任何内存空间?

【问题讨论】:

  • 你是说你在嵌入式系统上编译软件?
  • 不,很抱歉造成混乱。我在windows下编译生成二进制文件
  • 那么您在编译或运行可执行文件时是否空间不足?
  • typedefs 在编译后的图像中也不占用空间(尽管用它们定义变量可能)。
  • 什么类型的空间快用完了?用于变量的 RAM? ROM代码?您说“在转换(直接在编译后)到我们特定的二进制格式期间空间不足。”我不太明白这意味着你的空间用完了。

标签: c embedded memory-management


【解决方案1】:

不,#defines 不占用空间,除非它们被使用 - #defines 的工作方式类似于查找/替换;每当编译器看到左半部分时,它会在实际编译之前将其替换为右半部分。

所以,如果你有:

float f = SIGNAL1;

编译器会按字面意思解释语句:

float f = (float)0.03f;

它将永远看到 SIGNAL1,它不会出现在调试器中,等等。

【讨论】:

  • 实际上,预处理器进行宏替换。当源代码到达实际的编译器时,所有的宏调用在文本上都被它们定义的任何内容替换了。这意味着在宏中使用两次参数有些危险,因为如果参数类似于i++,则每次参数出现在宏扩展中时,i 都会递增。所以SIGNAL1_ISVALID(++i) 扩展为((++i &gt;= 0.0f) &amp;&amp; (++i &lt;= 10.0f))
  • @Chuck 你和我都知道这一点,但我试图让答案更容易理解 - 不过感谢您提及这一点!
  • 不出现在调试器中并不严格。例如:developer.apple.com/DOCUMENTATION/DeveloperTools/gdb/gdb/…(但通常是正确的,如果你假设这个,更容易理解答案;)
【解决方案2】:

这通常通过限制可能占用大量空间的 typedef 的数量来解决。

您似乎有些困惑,因为 typedef 在运行时不占用空间。它们只是数据类型的别名。现在您可能有大型结构的实例(typedef'd 或其他),但占用空间的是实例,而不是类型定义。我想知道这个声明中可能包含什么“等”。

宏实例在源代码中被它们的定义替换,并生成相应的代码,未使用的宏不会产生任何生成的代码。

占用空间的东西有:

  1. 可执行代码(函数/成员函数)
  2. 数据实例化(包括 C++ 对象实例)
  3. 分配给堆栈(或多线程系统中的堆栈)的空间量。

剩下的通常可用于动态内存分配 (RAM),或者未使用或用于非易失性存储 (Flash/EPROM)。

减少内存使用主要是选择/设计高效的数据结构、使用适当的数据类型以及高效的代码和算法设计。最好针对将获得最大收益的区域。要查看应用程序中对象和代码的大小,请获取链接器以生成映射文件。这将告诉您哪些是最大的函数,以及全局和静态对象的大小。

源文件文本长度不是代码大小的良好指南。大量的C代码是声明性的(一般头文件都是声明性的),不会产生占用内存的代码或数据。

嵌入式系统不一定意味着小内存,因此您应该指定。我曾在具有 64Mb RAM 和 2Mb 闪存的系统上工作过,即使与许多系统相比,这也是适度的。然而,具有片上资源的典型微控制器通常会少得多(尤其是占用大量芯片面积的 SRAM)。此外,您的系统是哈佛架构还是冯诺依曼架构在这里是相关的,因为在哈佛架构中,数据和代码空间是分开的,所以我们需要知道您缺少什么。如果是冯诺依曼,如果代码从 ROM 运行,或者是在运行时从 ROM 复制到 RAM(即不同类型的内存,即使它们位于相同的地址空间中),则代码/数据使用仍然相关.

克利福德

【讨论】:

    【解决方案3】:

    嗯,是的,也不是。

    不,未使用的#defines 不会增加生成的二进制文件的大小。

    是的,编译器在构建二进制文件时必须知道所有#defines(无论是使用的还是未使用的)。

    根据您的问题,您如何使用编译器有点模棱两可,但似乎您尝试直接在嵌入式设备上构建;你试过交叉编译器吗? :)

    【讨论】:

    • #defines 永远不会被编译器知道。它们只有预处理器知道,它使用它们进行文本替换和#if/#ifdef 语句。一旦我们离开预处理器并进入实际的编译器,#defines 就会全部被替换,并且不再存在(如果它们没有被替换,它们就会变成语法错误,或者更糟糕的是,链接器会丢失符号)。
    • P.S.很抱歉随机的固定宽度字体。现在我明白了 SO 用来匹配 code 块的正则表达式是如何工作的。
    • 啊,是的,但是在这个问题中的“松散”上下文中(OP 不指定/关心是编译器还是预处理器内存不足),我们可以假设预处理是编译过程的一部分。
    【解决方案4】:

    未使用的#defines 不会占用生成的可执行文件中的空间。它们确实在编译时占用了编译器本身的内存。

    【讨论】:

      猜你喜欢
      • 2011-01-30
      • 2014-03-07
      • 2020-05-21
      • 1970-01-01
      • 2012-03-02
      • 2012-04-20
      • 2012-04-05
      • 2011-03-12
      • 2019-09-14
      相关资源
      最近更新 更多