错误:'asm'未声明(首次使用此功能)

Bla*_*ero 10 c linux gcc inline-assembly

我在编译期间收到以下错误:

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

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

EXCHANGE( s, *(a) );
Run Code Online (Sandbox Code Playgroud)

并且宏的实际定义如下:

#define EXCHANGE(R,M) asm volatile ( "xchg   %1, %0" : "+m" (M), "+r" (R) )
Run Code Online (Sandbox Code Playgroud)

宏调用和定义存在于同一个头文件中.出了什么问题?

我正在使用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")
Run Code Online (Sandbox Code Playgroud)

und*_*gor 11

您正在编译选项-std=c99.

这会禁用某些非标准GCC扩展,例如该asm功能.

有关(非常精确的)文档,请参阅https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html#index-std-112.

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

  • 可以使用`-ansi`,`-std = c99`,`-ansi -pedantic`等标志与`__asm__`而不是`asm`.因为`__xx`是扩展名.标准允许扩展.参考:https://gcc.gnu.org/onlinedocs/gcc/Alternate-Keywords.html#Alternate-Keywords (3认同)

Cir*_*四事件 8

使用__asm__而不是asm使用-std=c99或使用-std=gnu99

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

asm关键字是GNU扩展.在编写可以使用-ansi和各种-std选项编译的代码时,请使用__asm__而不是asm(请参阅备用关键字).

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

-ansi和各种-std选项禁用某些关键字.当您想要使用GNU C扩展或所有程序(包括ISO C程序)都可以使用的通用头文件时,这会导致麻烦.关键字asm,typeof和inline在使用-ansi或-std编译的程序中不可用(尽管内联可以在使用-std = c99或-std = c11编译的程序中使用).ISO C99关键字限制仅在-std = gnu99(最终将是默认值)或-std = c99(或等效的-std = iso9899:1999)或后续标准版本的选项时才可用.

解决这些问题的方法是__在每个有问题的关键字的开头和结尾.例如,使用__asm__而不是asm,而__inline__不是内联.

其他C编译器不接受这些替代关键字; 如果要使用其他编译器进行编译,可以将备用关键字定义为宏,以使用常规关键字替换它们.它看起来像这样:

#ifndef __GNUC__
#define __asm__ asm
#endif
Run Code Online (Sandbox Code Playgroud)

-pedantic和其他选项会导致许多GNU C扩展的警告.您可以通过__extension__在表达式之前写入来防止在一个表达式中出现此类警告.__extension__除此之外没有任何影响.

-std=gnu99启用GNU扩展,例如asm,仍然保持C99语言.

C99标准

GCC的工作原理符合C99标准.从C99 N1256标准草案 7.1.3"保留标识符"1:

每个标头声明或定义其关联子条款中列出的所有标识符,并可选地声明或定义其关联的未来库方向子条款和标识符中列出的标识符,这些标识符始终保留用于任何用途或用作文件范围标识符.

  • 所有以下划线开头的标识符以及大写字母或另一个下划线始终保留用于任何用途.

否则,法律程序如:

int asm = 0;
Run Code Online (Sandbox Code Playgroud)

会变得非法.

测试程序

#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);
}
Run Code Online (Sandbox Code Playgroud)

在Ubuntu 17.10,GCC 7.2上测试.