C Macro技巧隐藏作业?

时间:2018-05-16 00:39:24

标签: c macros

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

问题是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时,它永远不会声明/ outta作用域。

我不想将var_name用于CUST2,它是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之前会删除注释:Can you #define a comment in C?

是否有一个聪明的宏技巧会隐藏/删除这个赋值,不会将local_var放在堆栈上?我觉得三元有可能,但我无法想到它。

修改的 最小的示例代码:

source1.c

int var_name = 0;

source1.h

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

source2.c

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

3 个答案:

答案 0 :(得分:1)

没有直接隐藏任务的方法,但有一些替代方案:

  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_name的所有作业替换为SET_VAR_TO(value),如:

    int foo(void) {
        /* Replace
        var_name = bar();
        * With: */
        SET_VAR_TO(bar());
    }
    
  2. 您可以测试是否在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());
    }
    
  3. 由于您不希望通过将每个分配包装在#ifdef CUST1 ... #endif中来重复代码,您可以使用该函数或宏。请记住,选项#1还会将宏SET_VAR_TO公开给#include的source1.h文件,而不仅仅是source2.c。

答案 1 :(得分:1)

extern int varname;

#define varname __attribute__((unused)) int varname

int square(int num) {
    varname = 1;
    return num * num;
}

除了-O0

之外,它可以在任何优化级别工作

https://godbolt.org/g/phssNn

答案 2 :(得分:1)

如果var_name未定义source2.c时无法访问CUST1中访问#include <stdlib.h> #define var_name (*(abort(), (type *)0)) 的代码(如您所说),那么您可以这样定义:

func scrollViewWillBeginZooming(_ scrollView: UIScrollView, with view: UIView?) {
     scrollView.pinchGestureRecognizer?.isEnabled = false
}

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