首页 > 解决方案 > 隐藏赋值的C宏技巧?

问题描述

我有一个包含少量文件的项目:source1.c source2.c source1.h source2.h。现在 source1.c 声明了一些变量,并且 source1.h 将它们外部化(使用条件构建宏)。source2.c 然后将通过为外部变量赋值来使用它们。

问题是 source1.h 具有以下内容:

#ifdef CUST1
extern type var_name;
#else
// Need to extern something or use a clever macro here but i dont like these below
//#define var_name int x (requires top of scope block usage)
//#define var_name // (doesnt compile)
//#define var_name -1 (simply doesnt compile)
//#define var_name 1= (This seems like it would reduce to unused 1==1; but doesnt work)
#endif

我的构建适用于 CUST1,但不适用于 CUST2,因为在 source2.c 中引用 var_name 时从未声明/超出范围。

我不想对 CUST2 使用 var_name,它是 source2.c 中无法访问的代码。这是我的问题,我如何使用宏来#define var_name 以便赋值“消失”或什么都不做?

我可以“#define var_name int x”。这会将 int x 放在 source2.c 函数中的堆栈上,并在 source2.c 中分配值,但如果它在除作用域块顶部之外的任何地方被引用,我的旧(C89?)编译器将出错。

例如,如果 source2.c 曾经有以下内容,它将无法编译:

unsigned short local_var = 0;
local_var = 1; //or someother value
var_name = local_var * 2;

我可以使用相同的 #ifdef CUST1 宏将逻辑包装在 source2.c 中,但这似乎也不太好。

如果 var_name 只是被比较,它不会那么糟糕,因为我可以只使用 #define var_name -1 或者会失败所有比较/切换的东西。问题是 -1 = temp_var; 无法编译,因为 -1 不能是左值。

类似地,我不能“#define var_name //”,因为在根据以下内容替换 marcos 之前删除了注释:你能在 C 中#define a comment 吗?

是否有一个巧妙的宏技巧可以隐藏/删除此分配,不会将 local_var 放在堆栈上?我觉得三元组有一些可能,但我想不出。

编辑 最小示例代码:

源1.c

int var_name = 0;

源1.h

#ifdef CUST1
extern int var_name;
#else
// clever macro
#endif

源代码2.c

#include "source1.h"
int main(){
  var_name = 1;
  return 0;
}

标签: cmacros

解决方案


没有像您建议的那样直接隐藏作业的方法,但有一些替代方法:

  1. 您可以使用另一个宏:

    #ifdef CUST1
    extern type var_name;
    /* Do the real assignment */
    #define SET_VAR_TO(val) do{ var_name = (val); } while(0)
    #else
    /* Just evaluate for the side-effects */
    #define SET_VAR_TO(val) do { val; } while(0)
    #endif
    

    然后在 source2.c 中将所有分配替换var_nameSET_VAR_TO(value)

    int foo(void) {
        /* Replace
        var_name = bar();
        * With: */
        SET_VAR_TO(bar());
    }
    
  2. 您可以测试是否CUST1也在 source2.c 中定义:

    /* in source2.c */
    int foo(void) {
    #ifdef CUST1
    var_name = bar();
    #endif
    }
    

    在这种情况下,您甚至可以将分配包装到仅在源文件中定义的真实函数:

    /* in source2.c */
    int set_var_to(type value) {
    #ifdef CUST1
    var_name = value;
    #endif
    }
    
    int foo(void) {
        /* Replace
        var_name = bar();
        * With: */
        set_var_to(bar());
    }
    

由于您不希望通过将每个分配包装在 an 中来重复代码,因此#ifdef CUST1 ... #endif您可以使用函数或宏。请记住,选项 #1 也会将宏暴露SET_VAR_TO给任何#includesource1.h 文件,而不仅仅是 source2.c。


推荐阅读