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

时间:2016-02-01 13:07:34

标签: c linux gcc inline-assembly

编译期间出现以下错误:

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")

3 个答案:

答案 0 :(得分:11)

您正在使用选项-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")

答案 1 :(得分: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

  

-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
     

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

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

C99标准

GCC的工作方式符合C99标准。来自C99 N1256 standard draft 7.1.3"保留标识符" 1:

  

每个标头声明或定义其相关子条款中列出的所有标识符,以及   可选地声明或定义其关联的未来库方向中列出的标识符   子条款和标识符,它们总是保留用于任何用途或用作文件   范围标识符。

     
      
  • 所有以下划线和大写字母或其他字母开头的标识符   下划线总是保留用于任何用途。
  •   

否则就是法律程序,如:

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上测试。

答案 2 :(得分:3)

asm是gcc扩展程序,因此您无法使用std=c99ansi等标记

更多细节 https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html#C-Extensions