C 中的模式设置:枚举、常量、定义

cle*_*enn 2 c embedded enums

我读过有关该主题的几个问题:

我知道在宏上通常首选#define枚举,以获得更好的封装和/或可读性。另外,它允许编译器检查类型以防止出现某些错误。

const声明介于两者之间,允许类型检查和封装,但更混乱。

现在我在内存空间非常有限的嵌入式应用程序中工作(我们经常必须争取字节节省)。我的第一个想法是常量比枚举占用更多的内存。但我意识到我不确定常数将如何出现在最终固件中。


例子:

enum { standby, starting, active, stoping } state;
Run Code Online (Sandbox Code Playgroud)

问题

在资源有限的环境中,enumVS#define与 VSstatic const在执行速度和内存占用方面如何比较?

cle*_*enn 6

为了尝试得到答案的一些实质内容,我做了一个简单的测试。

代码

我写了一个简单的 C 程序main.c

#include <stdio.h>

#include "constants.h"

// Define states
#define STATE_STANDBY 0
#define STATE_START   1
#define STATE_RUN     2
#define STATE_STOP    3

// Common code
void wait(unsigned int n)
{
  unsigned long int vLoop;

  for ( vLoop=0 ; vLoop<n*LOOP_SIZE ; ++vLoop )
  {
    if ( (vLoop % LOOP_SIZE) == 0 ) printf(".");
  }
  printf("\n");
}

int main ( int argc, char *argv[] )
{
  int state = 0;
  int loop_state;

  for ( loop_state=0 ; loop_state<MACHINE_LOOP ; ++loop_state)
  {
    if ( state == STATE_STANDBY )
    {
      printf("STANDBY ");
      wait(10);
      state = STATE_START;
    }
    else if ( state == STATE_START )
    {
      printf("START ");
      wait(20);
      state = STATE_RUN;
    }
    else if ( state == STATE_RUN )
    {
      printf("RUN ");
      wait(30);
      state = STATE_STOP;
    }
    else // ( state == STATE_STOP )
    {
      printf("STOP ");
      wait(20);
      state = STATE_STANDBY;
    }
  }

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

constants.h包含

#define LOOP_SIZE     10000000
#define MACHINE_LOOP  100
Run Code Online (Sandbox Code Playgroud)

我考虑了三种变体来定义状态常数。宏如上,枚举:

enum {
  STATE_STANDBY=0,
  STATE_START,
  STATE_RUN,
  STATE_STOP
} possible_states;
Run Code Online (Sandbox Code Playgroud)

const

static const int  STATE_STANDBY = 0;
static const int  STATE_START   = 1;
static const int  STATE_RUN     = 2;
static const int  STATE_STOP    = 3;
Run Code Online (Sandbox Code Playgroud)

而其余代码保持相同。

测试和结果

测试是在 64 位 Linux 机器上进行的,并使用以下命令进行编译gcc

全球规模

  • gcc main.c -o main给出

    宏:7310 字节
    枚举:7349 字节
    常量:7501 字节

  • gcc -O2 main.c -o main给出

    宏:7262 字节
    枚举:7301 字节
    常量:7262 字节

  • gcc -Os main.c -o main给出

    宏:7198 字节
    枚举:7237 字节
    常量:7198 字节

当优化打开时,const 和宏变体都具有相同的大小。枚举总是稍大一些。使用gcc -S我可以看到区别在于possible_states,4,4.comm。所以枚举总是比宏大。const 可以更大,但也可以优化掉。

断面尺寸

我使用以下文件检查了程序的几个部分objdump -h main:.text、.data、.rodata、.bss、.dynamic。在所有情况下,.bss 有 8 个字节,.data 有 16 个字节,.dynamic:480 个字节。

.rodata 有 31 个字节,非优化 const 版本(47 个字节)除外。

.text 从 620 字节到 780 字节,具体取决于优化。const unoptimized 是唯一一个具有相同标志的不同之处。

执行速度

我运行了该程序几次,但我没有注意到不同版本之间有实质性差异。在没有优化的情况下,它运行了大约50秒。使用 时可缩短至 20 秒-O2,使用 时可长达 3 分钟以上-Os。我用 测量了时间/usr/bin/time

内存使用情况

使用 时time -f %M,我在每种情况下得到大约 450k,而使用时valgrind --tool=massif --pages-as-heap=yes我在所有情况下得到 6242304。

结论

每当激活某些优化时,唯一显着的差异是枚举情况下多了大约 40 个字节。但没有 RAM 或速度差异。

关于范围、可读性……个人喜好的其他争论仍然存在。