【问题标题】:Variable no of argument in C MacroC宏中的变量号
【发布时间】:2012-02-16 16:10:50
【问题描述】:

我正在编写一些特定于硬件的代码,我想在其中使用 C 宏,宏定义将是这样的:-

#define VALIDATE_RESOURCE_AND_ALLOCATE(MODE,RESOURCE1) if(a[MODE][RESOURCE1] != x1) || \
                                                               (a[MODE][RESOURCE1] != y1)) \
                                                         a[MODE][RESOURCE1]=x3;

因为有时我可以分配超过 1 个资源,例如:-

#define VALIDATE_RESOURCE_AND_ALLOCATE_1(MODE,RESOURCE1,RESOURCE2) if(a[MODE][RESOURCE1] != x1) || \
                                                               (a[MODE][RESOURCE1] != y1)) \
                                                                         a[MODE][RESOURCE1]=x3;
                                                        if(a[MODE][RESOURCE2] != x1) || \
                                                               (a[MODE][RESOURCE2] != y1)) \
                                                         a[MODE][RESOURCE2]=x3;

我有什么办法可以编写一个宏,它涵盖了这两种情况,因为它需要可变数量的参数?

我在 printf 宏的宏中使用了可变数量的参数,但是我将如何使用它们各自的名称来处理这些参数,例如,如果我修改 MACRO 定义,例如:0-

#define VALIDA_RESOURCE_AND_ALLOCATE(MODE,.....) 

如何识别 RESOURCE1、RESOURCE2?

【问题讨论】:

  • 你“可以”但不能。你现在所拥有的工作。我将在第一个中重新定义第二个:#define VALIDATE_RESOURCE_AND_ALLOCATE_1(MODE, RESOURCE1, RESOURCE2) VALIDATE_RESOURCE_AND_ALLOCATE(MODE, RESOURCE1); VALIDATE_RESOURCE_AND_ALLOCATE(MODE, RESOURCE2),然后我会将它们中的 both 包装在 do { ... } while(0) 中,以便它们表现得像正确的语句。 (另外,不要使用分号的宏。)
  • 但是在这种情况下,如果假设第一个宏失败,我想退出,除非我检查它的返回值,否则这是不可能的......
  • 正如目前所写,这些宏都没有任何返回值。
  • 是的......我很抱歉不是很清楚......是的,但它应该返回一个错误代码,以防资源被使用。
  • 然后你需要重写它以返回所说的代码。我建议使用三元条件?:而不是if,然后用逗号运算符执行赋值并返回值(代码x = y, z会将y的值赋给x,但返回z 的值)。然后,对于双精度版本,您可以将这些返回值与布尔运算符(如果您希望短路行为并且返回值是通过/失败)或按位运算符(对于没有短路或更复杂的返回值)组合.就目前而言,我不知道你会实际返回什么。

标签: c unix macros embedded c99


【解决方案1】:

您的宏中有很多重复的代码。简化它们有助于使解决方案更加明显:

#define VALIDATE_RESOURCE_AND_ALLOCATE_1(MODE,RESOURCE1,RESOURCE2) do {\
    VALIDATE_RESOURCE_AND_ALLOCATE(MODE, RESOURCE1); \
    VALIDATE_RESOURCE_AND_ALLOCATE(MODE, RESOURCE2); \
} while(0)

在这里,更清楚的是,这只是在遍历参数列表时重复调用第一个宏。

假设您知道这里使用的数据类型将始终保持一致,您可以尝试这样的事情(未经测试并在我的脑海中写下):

#ifdef HARDWARE_PLATFORM_A
  static sometype args[] = {
      RESOURCE1,
      RESOURCE2,
      /* ... etc, etc */
  };
#elif defined HARDWARE_PLATFORM_B
  static sometype args[] = {
      RESOURCE10,
      RESOURCE11,
      /* ... etc, etc */
  };
/* repeat for all hardware platforms */
#endif

void initialization_function (void) {
    int i;
    for (i = 0; i < (sizeof(args) / sizeof(args[0])); ++i) {
        VALIDATE_RESOURCE_AND_ALLOCATE(MODE, args[i]);
    }
}

其中sometype 是您将用于RESOURCE1RESOURCE2 等的参数的数据类型。

鉴于您尝试做的事情的复杂性,您最好编写一个函数来进行迭代而不是宏。您仍然可以使用宏来创建RESOURCE 列表,但不要试图让预处理器为您进行迭代。如果您需要避免函数调用的开销(因为您将其标记为“嵌入式”),您可以声明函数inline,结果应该与使用宏一样高效。不过,在此过程中,您将获得诸如类型安全之类的东西。

虽然在技术上可能使用宏来做到这一点,但这将是一个令人讨厌的 hack,很可能会带来更多的问题而不是好处。使用预处理器执行复杂的程序性任务很少会得到很好的结果。

您拥有的另一种选择是使用代码生成器,它从文件中获取RESOURCE 参数列表并生成包含初始化代码的.c 文件。代码生成器将使用比 C 预处理器更强大的语言编写(几乎任何脚本语言都可以在这里使用)。不过,除非您有一长串 RESOURCEs,否则这可能不值得麻烦。

【讨论】:

    【解决方案2】:

    实现它的一种方法是不要传入可变数量的参数,而是坚持使用两个并使第二个成为可用于初始化的列表。例如(为了清楚起见,后面的反斜杠被省略了):

    #define VALIDATE_RESOURCE_AND_ALLOCATE(MODE, LIST)
    {
        int resources[] = LIST;
        int count;
        for(count = 0; count < sizeof(resources)/sizeof(int); count++) {
            /* do stuff here for each resources[count] */
        }
    }
    

    然后你可以简单地这样称呼它:

    VALIDATE_RESOURCE_AND_ALLOCATE(MODE, { RESOURCE1, RESOURCE2 } )
    

    注意:给这只猫剥皮的方法不止一种,所以选择你最喜欢的答案并继续吧:-)

    【讨论】:

    • 那不是“赋值”,那是“初始化”。请注意,初始化允许使用 { RESOURCE1, RESOURCE2 },我怀疑这是您的意图:仅仅分配不允许这样做。
    • 这不起作用,因为预处理器会将{ RESOURCE1RESOURCE2 } 视为两个参数,而不是包含逗号的单个参数。
    • @ChrisDodd - 天哪,我忘了。不过,我认为将其括在括号中仍然有效。 (作为一个黑客,你可以将LIST 变成__VA_LIST__ 并希望人们做对了,但这似乎是不可取的。)
    • 是的,你当然是对的。你实际上可以在 ()s 中传递东西。但这无济于事,因为初始化不会采用与它们一起传入的 ()。否则(1, ({2,3})) 会起作用。但是你最终不得不创建一个函数,它接受第二个参数并返回一个静态数组指针或其他东西,然后它开始感觉真的 hacky。
    【解决方案3】:

    这会不会太傻了? ;-)

    #define VALIDATE_RESOURCE_AND_ALLOCATE(MODE,RESOURCE1,RESOURCE2)                \
    if(a[MODE][RESOURCE1] != x1) || (a[MODE][RESOURCE1] != y1))                     \
    a[MODE][RESOURCE1]=x3;                                      \
    if((RESOURCE1 != RESOURCE2) && (a[MODE][RESOURCE2] != x1) || (a[MODE][RESOURCE2] != y1)))   \
    a[MODE][RESOURCE2]=x3;
    

    并为单个资源如下调用它

    VALIDATE_RESOURCE_AND_ALLOCATE(M1,R1,R1)
    

    像下面这样两个?

    VALIDATE_RESOURCE_AND_ALLOCATE(M1,R1,R2)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-08
      • 1970-01-01
      • 2012-11-30
      相关资源
      最近更新 更多