error: ‘asm’ undeclared (first use in this function)

error: ‘asm’ undeclared (first use in this function)

我在编译过程中遇到以下错误:

error: ‘asm’ undeclared (first use in this function)
 EXCHANGE( s, *(a) );
 ^

在调用宏的头文件中,如下所示:

EXCHANGE( s, *(a) );

而宏的实际定义如下:

#define EXCHANGE(R,M) asm volatile ( "xchg   %1, %0" : "+m" (M), "+r" (R) )

宏调用和定义存在于同一个头文件中。 怎么了?

我正在使用CMAKE构建项目,CFLAGS如下:

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Werror")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wextra")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-braces")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-missing-field-initializers")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wformat=2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wswitch-default")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wcast-align")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wpointer-arith")
#-Wno-deprecated-declarations to suppress the deprecation errors with newer version of JSON-C 
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-deprecated-declarations")
#set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wbad-function-cast")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-overflow=5")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Winline")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wundef")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wnested-externs")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-cast-qual")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wshadow")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wunreachable-code")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wfloat-equal")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wstrict-aliasing=2")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wredundant-decls")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wold-style-definition")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wno-unused-parameter")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")

#set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -O0 -g3 -ggdb")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -O3")
set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS} -E")

您正在使用选项 -std=c99 进行编译。

这会禁用一些非标准的 GCC 扩展,例如 asm 功能。

请参阅 https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html#index-std-112 了解一些(不是很精确的)文档。

如果您需要内联汇编,请从您的 cmakefile 中删除或更改行 set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99")

asm 是 gcc 扩展,因此您不能使用 std=c99ansi

等标志

更多详细信息,请访问 https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions

要么使用 __asm__ 而不是 asm-std=c99,或者使用 -std=gnu99

来自 GCC 文档 https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Extended-Asm.html

The asm keyword is a GNU extension. When writing code that can be compiled with -ansi and the various -std options, use __asm__ instead of asm (see Alternate Keywords).

https://gcc.gnu.org/onlinedocs/gcc-7.2.0/gcc/Alternate-Keywords.html#Alternate-Keywords

-ansi and the various -std options disable certain keywords. This causes trouble when you want to use GNU C extensions, or a general-purpose header file that should be usable by all programs, including ISO C programs. The keywords asm, typeof and inline are not available in programs compiled with -ansi or -std (although inline can be used in a program compiled with -std=c99 or -std=c11). The ISO C99 keyword restrict is only available when -std=gnu99 (which will eventually be the default) or -std=c99 (or the equivalent -std=iso9899:1999), or an option for a later standard version, is used.

The way to solve these problems is to put __ at the beginning and end of each problematical keyword. For example, use __asm__ instead of asm, and __inline__ instead of inline.

Other C compilers won’t accept these alternative keywords; if you want to compile with another compiler, you can define the alternate keywords as macros to replace them with the customary keywords. It looks like this:

#ifndef __GNUC__
#define __asm__ asm
#endif

-pedantic and other options cause warnings for many GNU C extensions. You can prevent such warnings within one expression by writing __extension__ before the expression. __extension__ has no effect aside from this.

-std=gnu99 启用 GNU 扩展,例如 asm,同时仍保持类似 C99 的语言。

C99 标准

GCC 这样工作以符合 C99 标准,该标准将双下划线符号标记为保留。

来自C99 N1256 standard draft 7.1.3“保留标识符”1:

Each header declares or defines all identifiers listed in its associated subclause, and optionally declares or defines identifiers listed in its associated future library directions subclause and identifiers which are always reserved either for any use or for use as file scope identifiers.

  • All identifiers that begin with an underscore and either an uppercase letter or another underscore are always reserved for any use.

否则,如果预定义了 asm,则合法程序如:

int asm = 0;

会变成非法的。

测试程序

#include <assert.h>
#include <stdint.h>

int main(void) {
    uint32_t io = 0;
    __asm__ volatile (
        "movl %0, %%eax;"
        "inc %%eax;"
        "movl %%eax, %0;"
        : "+m" (io)
        :
        : "%eax"
    );
    assert(io == 1);
}

在 Ubuntu 17.10,GCC 7.2 上测试。