do..while(0) c2hs 中类似函数的 C 宏包装器

do..while(0) function-like C macro wrapper in c2hs

我想在 C 函数中包装一个类似函数的 C 宏(然后用 {#fun ... #} 块将其包装在 Haskell 中),但是 c2hs do.. while(0) 语法预处理器阻塞; 这是代码:

module TestMacro where
#c

#define TestF1(n) do{if n==0 return 0;else return 1; } while(0)

int c_testF1(int x)
{ return ( TestF1(x) ); }

#endc

这是错误:

c2hs TestMacro.chs
c2hs: C header contains errors:

TestMacro.chs.h:6: (column 12) [ERROR]  >>> Syntax error !
  The symbol `do' does not fit here.

make: *** [main] Error 1

我做错了什么? 我的目标是包装 PETSc 库的 CHKERRQ 宏,在 petscerror.h 中定义如下(为了便于阅读,分成多行):

#define CHKERRQ(n)             
    do {if (PetscUnlikely(n)) 
        return PetscError(PETSC_COMM_SELF,__LINE__,PETSC_FUNCTION_NAME,__FILE__,n,PETSC_ERROR_REPEAT," ");} 
    while (0)
{ return ( TestF1(c) ); }

return 的语法需要一个(可选的)表达式:您不能使用语句代替表达式。 do {} while (0) 是一个语句。

(C11, 6.8.6 Jump statements)

Syntax

return expression_opt ;

您可以改为使用:

int c_testF1(int x)
{ TestF1(c); }

正如我在评论中所说,这会起作用,但我不建议这样做,这是糟糕的编码风格。 ?: 可以在示例 TestF1 宏中使用(如另一个答案中所写)但它不能用于您的 CHKERRQ 实际用例(您可以将宏用于 PetscError 函数调用)。

请记住,#define 是文本替换。所以

{ return ( TestF1(c) ); }

变成

{ return ( do{if c==0 return 0;else return 1; } while(0) ); }

并且您既不能使用 do { .. } while() 也不能使用其他 return 语句作为 return 参数(并且缺少 ìf 周围的括号 - 条件)。为了让你的宏在那个地方工作,它可以简单地定义为

#define TestF1(n)    ((n)==0 ? 0 : 1)

编辑

使用 CHKERRQ 的函数可能如下所示

int my_chkerrq( int n )
{
     CHKERRQ(n);
     return( whatever_you_want_to_return_here );
}

但我建议直接调用 CHKERRQ() 调用的内容:

int my_chkerrq( int n )
{
     if (PetscUnlikely(n)) 
         return( PetscError(PETSC_COMM_SELF,__LINE__,PETSC_FUNCTION_NAME,__FILE__,n,PETSC_ERROR_REPEAT," ") );
     else 
         return( whatever_you_want_to_return_here );
}

当然,在这两种情况下,__LINE____FILE__ 都被 C 代码中的那些替换了,在 Haskell 环境中可能不是很有用