C宏隐藏赋值的技巧?

C宏隐藏赋值的技巧?,c,macros,C,Macros,我有一个包含少量文件的项目: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 do

我有一个包含少量文件的项目: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时,它从未声明/超出作用域

extern int varname;

#define varname __attribute__((unused)) int varname

int square(int num) {
    varname = 1;
    return num * num;
}
我不想为CUST2使用var_名称,它在source2.c中是不可访问的代码。我的问题是,如何使用宏定义变量名,使赋值“消失”或什么也不做?

我可以“定义变量名intx”。这将把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#u name只是与之进行比较,那就不会那么糟糕了,因为我可以只使用#define var#u name-1,或者使用一些会使所有比较/开关失败的东西。问题是-1=临时变量;无法编译,因为-1不能是左值

类似地,我不能“#定义变量名//”,因为注释在替换Marco之前会被删除,如下所示:

是否有一个聪明的宏技巧可以隐藏/删除这个赋值,而不会在堆栈上放置本地变量?我觉得三元组有可能,但我想不起来

编辑 最小示例代码:

资料来源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;
}

没有直接的方法可以隐藏您提议的任务,但是有一些替代方法:

  • 您可以使用另一个宏:

    #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\u name
    的所有赋值,并将其设置为(value)类似:

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

    /* 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());
    }
    
  • 因为您不希望通过将每个分配包装在
    #ifdef CUST1中来复制代码#endif
    您可以使用函数或宏。请记住,选项#1还将向任何包含#s source1.h而不仅仅是source2.c的文件公开宏
    SET#VAR#u TO

    extern int varname;
    
    #define varname __attribute__((unused)) int varname
    
    int square(int num) {
        varname = 1;
        return num * num;
    }
    
    它将在除-O0之外的任何优化级别上工作


    如果在
    source2.c
    中访问
    var\u name
    的代码在未定义
    CUST1
    时无法访问(正如您所说),则可以这样定义它:

    #include <stdlib.h>
    
    #define var_name (*(abort(), (type *)0))
    
    #包括
    #定义变量名称(*(abort(),(type*)0))
    

    这将在语法上作为正确类型的左值(或右值)工作,但如果程序实际执行过,将中止程序。

    。不要用另一种混乱程度来隐藏混乱的代码。修复基本问题。如果
    var#u name
    是CUST1 only,那么您需要
    \ifdef
    全部使用它,或者只在大多数地方使用它,只在不希望它可见的地方使用它。@AndrewHenle我同意这一点,基本问题是在为CUSTOMER2编译项目时分配它。“基本解决方案”是将逻辑封装在#ifdef CUST1宏中使用的地方,但扩展性不太好。有两个以上的客户,现在var_名称已被外部化,今后可能会在其他地方使用。我同意你的观点,这会使事情变得过于复杂,但事情就是这样。问题是关于隐藏CUSTOMER2赋值的宏技术。请澄清您是否希望将赋值转换为(a)无操作,(b)编译错误,或(c)运行时错误。在C99中,您可以执行
    #定义变量名(int[]){0}[0]
    感谢您的响应。如果我可以“#define var_name 1=”那么主要是1==1;不会影响和“吸收”CUST2案件中的转让。但这似乎对我还不起作用。你的两个解决方案都有效,如果我想不出更好的办法,我可能会实施第一个方案,并将你的回答视为答案,但我仍然不相信有什么聪明的办法可以吸收这项任务。
    set_var_to()
    甚至可以是
    source1.h
    中的
    静态内联
    函数,因此函数调用在
    中编译为空!CUST1
    案例。感谢您的回复,peter。如果C89不在作用域块的顶部,它还会引发编译器错误吗?它似乎声明它未被使用,但是它仍然声明它和声明在中间块的中间,对于我的一些客户来说失败编译。顺便说一句,我不明白为什么