当前位置: 首页 > 工具软件 > asdf > 使用案例 >

神奇的'asdf;'错误

陶俊晤
2023-12-01

神奇的’asdf;‘错误

1. 问题的由来

编译代码时,有时候会根据宏设置进行条件编译,例如u-boot的代码common\board_r.c中:

static int run_main_loop(void)
{
#ifdef CONFIG_SANDBOX
    sandbox_main_loop_init();
#endif
    /* main_loop() can return to retry autoboot, if so just run it again */
    for (;;)
        main_loop();
    return 0;
}

代码会根据宏CONFIG_SANDBOX是否定义来决定是否编译对sandbox_main_loop_init()函数的调用。

如果不清楚宏的意义和设置,但又想知道宏包含的代码是否参与编译,比较省事的办法是在宏包含的代码片段内添加一个非法语句。因为插入了非法语句,如果需要编译,那肯定会出现编译错误。

我以前就喜欢用asdf;为了让这个非法语句看起来像一个正常语句,在语句末尾特意添加了分号;)。

谁想,这里面其实有个坑。

2. asdf;实验

2.1 例子

下面以Hello World为例说明。

  • Hello World例子
    hello.c
#include <stdio.h>

int main(int argc, char *argv[])
{
        printf("hello world!\n");

        return 0;
}

编译hello.c,一切正常:

ygu@stb-lab-04:/opt/ygu/example$ gcc -o hello hello.c
ygu@stb-lab-04:/opt/ygu/example$ ls -al
total 28
drwxrwxr-x 2 ygu ygu 4096 Oct 10 17:50 .
drwxr-xr-x 6 ygu ygu 4096 Oct 10 17:44 ..
-rwxrwxr-x 1 ygu ygu 8519 Oct 10 17:45 hello
-rw-rw-r-- 1 ygu ygu   96 Oct 10 17:44 hello.c
  • 函数内的asdf;

main函数内添加非法语句asdf;hello1.c

#include <stdio.h>

int main(int argc, char *argv[])
{
        asdf;

        printf("hello world!\n");

        return 0;
}

无法通过编译,跟预期的一样:

ygu@stb-lab-04:/opt/ygu/example$ gcc -o hello1 hello1.c 
hello1.c: In function 'main':
hello1.c:5:2: error: 'asdf' undeclared (first use in this function)
  asdf;
  ^
hello1.c:5:2: note: each undeclared identifier is reported only once for each function it appears in
ygu@stb-lab-04:/opt/ygu/example$ ls -al
total 28
drwxrwxr-x 2 ygu ygu 4096 Oct 10 17:50 .
drwxr-xr-x 6 ygu ygu 4096 Oct 10 17:44 ..
-rwxrwxr-x 1 ygu ygu 8519 Oct 10 17:45 hello
-rw-rw-r-- 1 ygu ygu   96 Oct 10 17:44 hello.c
-rw-rw-r-- 1 ygu ygu  104 Oct 10 17:50 hello1.c
  • 函数外的asdf;

如果将这个asdf;添加到函数外,会怎样呢?

main函数外添加非法语句asdf;hello2.c

#include <stdio.h>

asdf;

int main(int argc, char *argv[])
{
        printf("hello world!\n");

        return 0;
}

居然能通过编译,好意外:

ygu@stb-lab-04:/opt/ygu/example$ gcc -o hello2 hello2.c
hello2.c:3:1: warning: data definition has no type or storage class [enabled by default]
 asdf;
 ^
ygu@stb-lab-04:/opt/ygu/example$ ls -lh
total 36K
-rwxrwxr-x 1 ygu ygu 8.4K Oct 10 17:45 hello
-rw-rw-r-- 1 ygu ygu   96 Oct 10 17:44 hello.c
-rw-rw-r-- 1 ygu ygu  104 Oct 10 17:50 hello1.c
-rwxrwxr-x 1 ygu ygu 8.4K Oct 10 18:02 hello2
-rw-rw-r-- 1 ygu ygu  103 Oct 10 17:59 hello2.c

2.2 实验结论

为什么asdf;添加在不同的地方,结果不一样呢?

  • 函数内的asdf;

不能通过编译,报错:

hello1.c: In function 'main':
hello1.c:5:2: error: 'asdf' undeclared (first use in this function)
  asdf;
  ^
hello1.c:5:2: note: each undeclared identifier is reported only once for each function it appears in

从错误信息看,编译器认为这里的asdf是未声明的标识符(undeclared identifier)。

  • 函数外的asdf;

可以通过编译,但有一个警告信息:

hello2.c:3:1: warning: data definition has no type or storage class [enabled by default]
 asdf;
 ^

编译器认为asdf;是一个数据定义语句,其定义了数据asdf,但是没有指定数据的类型或类别。

根据默认的行为,asdf的数据类型会被认为是整形int
因此,这里相当于是定义了一个未被使用的int型变量asdf,也就不难理解为什么可以通过编译了。

为了验证asdf被默认认为是int而不是其它,可以尝试在代码里面对asdf赋值一个指针:

char c = 'a'; asdf = &c;

编译会输出警告信息:

warning: assignment makes integer from pointer without a cast [enabled by default]

warning提示这里尝试将pointer赋值给integer而没有强制类型转换

3. 结论

尽量不要使用带分号’;‘的语句(如:’asdf;‘)来检查代码是否被宏条件语句编译。

如果要用非法语句来检查,也不要加分号’;

 类似资料: