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

时间:2015-04-23 17:23:16

标签: c haskell c-preprocessor petsc c2hs

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

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)

2 个答案:

答案 0 :(得分:9)

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

{ return ( TestF1(c) ); }

变为

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

并且您既不能使用do { .. } while()也不能使用其他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环境中可能不是很有用

答案 1 :(得分:5)

{ return ( TestF1(c) ); }

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

  

(C11,6.8.6跳转声明)

     

语法

     

return expression_opt;

你可以做的是改为:

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

正如我在评论中提到的那样可行,但我不建议这样做,这是错误的编码风格。 ?:可以在示例TestF1宏中使用(如另一个答案中所述),但它不能用于CHKERRQ实际用例(您可以使用宏来表示PetscError 1}}函数调用虽然)。