【问题标题】:Set buffer contents as defined in header file macros设置头文件宏中定义的缓冲区内容
【发布时间】:2022-01-11 18:53:03
【问题描述】:

我有各种uint8_t 类型的数组内容“模板”,我想在一个特殊的头文件中定义它们。这些内容模板也有不同的长度:

#define CONTENT_VARIANT_A { 5, 3, 8, 1, 4, 23 }
#define CONTENT_VARIANT_B { 1, 10, 2 }
#define CONTENT_VARIANT_C { 4, 39, 2, 39 }
// '0' is not a valid element value (=> can be used for loop termination)

#define CONTENT_MAX_SIZE = 20;

在我的代码中,我希望有一种方法可以将数组缓冲区的内容设置为这些预定义值之一。这是我目前的代码,使用switchmemcpy

设置内容的方法:

void SetBuffer(uint8_t *my_buffer, uint8_t chosen_content) {
  memset(my_buffer, 0, CONTENT_MAX_SIZE);
  switch (chosen_content) {
    case CHOICE_VARIANT_A: {
      uint8_t new_content[] = CONTENT_VARIANT_A;
      memcpy(my_buffer, new_content, sizeof(new_content));
      break;
    }
    case CHOICE_VARIANT_B: {
      uint8_t new_content[] = CONTENT_VARIANT_B;
      memcpy(my_buffer, new_content, sizeof(new_content));
      break;
    }
    case CHOICE_VARIANT_C: {
      uint8_t new_content[] = CONTENT_VARIANT_C;
      memcpy(my_buffer, new_content, sizeof(new_content));
      break;
    }
  }
}

用法:

// Buffer declaration (done once)
uint8_t my_buffer[CONTENT_MAX_SIZE] = { 0 };

// Buffer population + usage (executed multiple times, with varying values for 'chosen_content')
SetBuffer(my_buffer, chosen_content);
uint8_t i = 0;
while (i < CONTENT_MAX_SIZE && my_buffer[i] > 0) {
  // ...
  ++i;
}

我是一名 C# 程序员,并且是 C 的新手; SetBuffer 中的代码对我来说似乎过于复杂,但这是我唯一能想到的应该工作的东西(关于我认为我对 C 的了解),而且它也可以编译。这是做我想做的事情的正确方法,还是完全不同,应该做完全不同的事情?

【问题讨论】:

    标签: arrays c macros memcpy


    【解决方案1】:

    如果不需要清零,您可以将函数缩减为如下所示:

    void SetBuffer(uint8_t *my_buffer, uint8_t chosen_content) {
      
      switch (chosen_content) {
        case CHOICE_VARIANT_A: memcpy(my_buffer, (uint8_t[])CONTENT_VARIANT_A, sizeof((uint8_t[])CONTENT_VARIANT_A)); break;
        case CHOICE_VARIANT_B: memcpy(my_buffer, (uint8_t[])CONTENT_VARIANT_B, sizeof((uint8_t[])CONTENT_VARIANT_B)); break;
        case CHOICE_VARIANT_C: memcpy(my_buffer, (uint8_t[])CONTENT_VARIANT_C, sizeof((uint8_t[])CONTENT_VARIANT_C)); break;
      }
    }
    

    其中(uint8_t[])CONTENT_VARIANT_A 不是强制转换,但与宏一起形成复合文字。本质上是一个本地的匿名临时数组。 sizeof 表达式类似,并在编译时计算。

    如果您必须将未使用的单元格清零,则将(uint8_t[]) 替换为(uint8_t[CONTENT_MAX_SIZE])。 C 保证不包含在初始化列表中的项目被设置为零。

    另一个速度超过可读性的替代方法是一个邪恶的宏:

    #define SetBuffer(my_buffer, content)         \
    memcpy(my_buffer,                             \ 
           (uint8_t[])CONTENT_VARIANT_##content,  \
           (uint8_t[])CONTENT_VARIANT_##content)
    

    调用SetBuffer(buf, A); 等。这是相当安全的类型,因为未知字母前缀会导致编译器错误。您可能还想问自己为什么不简单地在调用方使用memcpy

    【讨论】:

    • 现在每个 case 都是 1 行,在调用方编写它成为一种选择。以前,冗长的开关会使其他功能变得太长。我想知道 - 如果我在 C 文件的顶部定义它并在底部取消定义它,宏还会是邪恶的吗?因为老实说,我认为像 LoadPreset(my_buffer, A) 这样的东西比具有非常相似但长开关线的函数提高了可读性。
    猜你喜欢
    • 2017-12-14
    • 1970-01-01
    • 2015-08-20
    • 2021-09-26
    • 1970-01-01
    • 2019-09-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多