do..while(0) функционально-подобная оболочка макроса C в c2hs
Я хотел бы обернуть функциональный макрос C в функцию C (и, в свою очередь, обернуть его в Haskell с помощью {#fun ... #}
блок), но 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
Что я делаю неправильно? Моя цель - завернуть CHKERRQ
макрос библиотеки PETSc, определяемый следующим образом: 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 ответа
Помни что #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
{ return ( TestF1(c) ); }
Синтаксис return
требует (необязательного) выражения: вы не можете использовать выражение вместо выражения. do {} while (0)
это утверждение.
(C11, 6.8.6 операторы переходов)
Синтаксис
return expression_opt;
Вместо этого вы можете использовать:
int c_testF1(int x)
{ TestF1(c); }
Как я добавил в комментариях, это будет работать, но я не советую это делать, это плохой стиль кодирования. ?:
может быть использован в примере TestF1
макрос (как написано в другом ответе), но он не может быть использован для вашего CHKERRQ
реальный вариант использования (вы можете использовать макрос для PetscError
хотя вызов функции).