如何处理错误:没有“do”时“do”之前的预期表达式?

Alp*_*uri 1 c compiler-errors alsa

我收到以下编译器错误,即使我的代码中没有“do”表达式。

gcc -Wall -g -c main.c -lasound
In file included from /usr/include/alsa/asoundlib.h:49:0,
                 from main.c:2:
main.c: In function ‘main’:
main.c:8:5: error: expected expression before ‘do’
  if(snd_pcm_hw_params_alloca(&params) < 0) {
     ^
main.c:6:30: warning: unused variable ‘params’ [-Wunused-variable]
         snd_pcm_hw_params_t *params;
                              ^~~~~~
Makefile:15: recipe for target 'main.o' failed
make: *** [main.o] Error 1
Run Code Online (Sandbox Code Playgroud)

从以下最小可重现示例中:

#include <stdio.h>
#include <alsa/asoundlib.h>

int main(int argc, char **argv)
{       
        snd_pcm_hw_params_t *params;

        if(snd_pcm_hw_params_alloca(&params) < 0) {
                return 0;
        }

        exit(0);
}
Run Code Online (Sandbox Code Playgroud)

我知道这不是有效的 ALSA 程序。我也知道似乎 snd_pcm_hw_params_alloca() 甚至没有返回任何值得检查错误的东西?但这无关紧要,无论如何这都应该是有效的 C 代码,即使它滥用 API。

“做”的表达在哪里?如果我转到 /usr/include/alsa/asoundlib.h 并在那里闲逛,我看不到任何明显表明存在问题的东西。

如果我删除条件 if 测试,并得到:

#include <stdio.h>
#include <alsa/asoundlib.h>

int main(int argc, char **argv)
{
        snd_pcm_hw_params_t *params;

        snd_pcm_hw_params_alloca(&params);

        exit(0);
}
Run Code Online (Sandbox Code Playgroud)

这将编译没有错误。

这是什么?

如果我查看 pcm.h,我会看到:

#define snd_pcm_hw_params_alloca(ptr) __snd_alloca(ptr, snd_pcm_hw_params)
int snd_pcm_hw_params_malloc(snd_pcm_hw_params_t **ptr);
void snd_pcm_hw_params_free(snd_pcm_hw_params_t *obj);
void snd_pcm_hw_params_copy(snd_pcm_hw_params_t *dst, const snd_pcm_hw_params_t *src);
Run Code Online (Sandbox Code Playgroud)

然而,这并没有告诉我任何事情。为什么编译器会产生这个错误?

Die*_*Epp 5

我也知道似乎 snd_pcm_hw_params_alloca() 甚至没有返回任何值得检查错误的东西?但这无关紧要,无论如何这都应该是有效的 C 代码,即使它滥用 API。

不,如果snd_pcm_hw_params_alloca()没有值,则不能将其与 0 进行比较。例如,以下内容也是无效的:

void func(void) { }
void other(void) {
    if (func() < 0) { // Error
    }
}
Run Code Online (Sandbox Code Playgroud)

实际上,snd_pcm_hw_params_alloca()是一个宏,它是另一个宏的包装器,__snd_alloca. 该do是有使它更像一个声明。您只能在自己的行上或在do循环合法的任何其他地方将其称为语句。

snd_pcm_hw_params_alloca(&params);
Run Code Online (Sandbox Code Playgroud)

您无法检查错误,因为alloca()不检查错误。如果alloca()失败,它只会踩在你的筹码上,糟糕的事情就会发生。除了不使用之外,您无能为力alloca()(这就是为什么您可能会听到避免使用 alloca 的建议)。

有关为什么使用do循环的解释,请参阅:C 多行宏:do/while(0) 与作用域块

有关alloca()工作原理的更多信息,请参阅:为什么使用 alloca() 不被视为良好实践?