是否可以在#define中使用if语句?

时间:2012-10-20 14:17:40

标签: c if-statement macros c-preprocessor

我正在尝试使用以下公式制作一个宏:(a^2/(a+b))*b,我想确保没有除以零。

#define SUM_A( x, y ) if( x == 0 || y == 0) { 0 } else { ( ( ( x * x ) / ( ( x ) + ( y ) ) ) * ( y ) )}

然后我在main中调用宏:

float a = 40, b = 10, result; 
result = SUM_A(a, b); 
printf("%f", result);

我尝试在if函数周围使用括号,但我在if语句之前一直遇到语法错误。我也尝试过使用return,但我在某处读到你不应该在define中使用它。

8 个答案:

答案 0 :(得分:21)

您不能使用if语句,因为#define由预处理器解释,输出将是

 result=if( x == 0 || y == 0) { 0 } else { ( ( ( x * x ) / ( ( x ) + ( y ) ) ) * ( y ) )}

这是错误的语法。

但另一种方法是使用三元运算符。将您的定义更改为

#define SUM_A( x, y )  ((x) == 0 || (y) == 0 ? 0 : ( ( ( (x) * (x) ) / ( ( x ) + ( y ) ) ) * ( y ) ))

请记住始终将您的定义放在括号之间,以避免在替换时出现语法错误。

答案 1 :(得分:6)

if引入了一个陈述,而不是一个表达。使用“三元”(条件)运算符:

#define SUM_A(x, y) (((x) == 0 || (y) == 0)? 0: ((((x) * (x)) / ((x) + (y))) * (y)))

或者,将其设为inline函数:

inline float sum_a(float x, float y)
{
    if (x == 0 || y == 0)
        return 0;
    else
        return ((x * x) / (x + y)) * y;
}

这避免了对x和/或y进行多次评估的问题,并且更具可读性,但它确实修复了xy的类型。您也可以删除inline并让编译器决定是否值得内联此函数(inline不保证它将执行内联)。

答案 2 :(得分:4)

从技术上讲,可以在if中使用#define语句(但不是您期望的方式)。由于#define只是文本替换,因此您必须非常小心如何扩展它。我发现这个有用......

#define SUM_A(x, y)                                        \
({                                                         \
    double answer;                                         \
    if ((x) == 0 || (y) == 0)                              \
        answer = 0;                                        \
    else                                                   \
        answer = ((double)((x)*(x)) / ((x)+(y))) * (y);    \
    (answer);                                              \
})
// Typecasting to double necessary, since int/int == int in C

这应该会为您提供您正在寻找的结果,并且没有理由不能将其扩展为包含多个else if(尽管其他答案也是如此)指出,使用三元运算符可能更容易。)

答案 3 :(得分:1)

问题是if语句不是表达式,并且不返回值。此外,在这种情况下没有充分的理由使用宏。实际上,它可能会导致非常严重的性能问题(取决于您作为宏参数传递的内容)。你应该使用一个函数。

答案 4 :(得分:1)

您的宏存在多个问题:

  • 它会扩展为语句,因此您无法将其用作表达式

  • 参数在扩展中没有正确括号:使用除变量名或常量之外的任何内容调用此宏都会产生问题。

  • 多次计算参数:如果调用带有副作用的宏,例如SUM_A(a(), b())SUM_A(*p++, 2),副作用将多次出现。

要避免所有这些问题,请使用可能定义为static inline的函数来帮助编译器优化更多(这是可选的,现代编译器会自动执行此操作):

static inline int SUM_A(float x, float y) {
    if (x == 0 || y == 0)
        return 0; 
    else
        return x * x / (x + y) * y;
}

注意:

  • 此函数使用浮点运算,宏不一定取决于其参数的实际类型。
  • 测试不会阻止除零:SUM_A(-1,1)仍然执行一次。
  • 除以零不一定是个问题:使用浮点参数,它会产生无穷大或NaN,而不是运行时错误。

答案 5 :(得分:0)

是的,您可以在宏中使用if语句。您需要正确格式化。这是一个例子:

#define MY_FUNCTION( x )  if( x ) { PRINT("TRUE"); } else { PRINT("FALSE"); } 

答案 6 :(得分:0)

我使用具有一定条件的宏,并且确实有合法用途。

我有一些本质上是斑点的结构,一切都只是一个uint8_t流。

为了使内部结构更具可读性,我有条件宏。

示例...

#define MAX_NODES 10
#define _CVAL16(x)(((x) <= 127) ? (x) : ((((x) & 127) | 0x80) ), ((x) >> 7))  // 1 or 2 bytes emitted <= 127 = 1 otherwise 2

现在可以在数组内使用宏了...

uint8_t arr_cvals[] = { _CVAL16(MAX_NODES), _CVAL16(345) };

在数组中发出三个字节,第一个宏发出1,第二个宏发出2。这是在编译时评估的,只是使代码更具可读性。

我也有...例如...

#define _VAL16(x) ((x) & 255), (((x) >> 8) & 255)

对于最初的问题...也许这个人想将结果与常量一起使用,但实际上还是要归结到使用它的位置和方式。

#define SUM_A(x, y) (!(x) || !(y)) ? 0 : ((x) * (x) / ((x) + (y)) * (y))
float arr_f[] = { SUM_A(0.5f, 0.55f), SUM_A(0.0f, -1.0f), SUM_A(1.0f, 0.0f) };

在运行时可以拥有...

float x;
float y;

float res = SUM_A(x,y); // note ; on the end

我有一个程序来创建字体,这些字体被包含在C程序的代码中,并且大多数值都被包裹在宏中,这些宏将32位值分成4个字节,浮点为4个字节,等等。

答案 7 :(得分:0)

您可以将条件语句转换为简单表达式。条件评估为@SuppressWarnings("unchecked") ArrayList<Map<String, Object>> items = (ArrayList<Map<String, Object>>) value; 0

1

根据您的具体情况

// pseudo-code
// if (<something>) { 0; } else { 42; }
// if (!<something>) { 42; } else { 0; }
// !<something> * 42;