Ошибка: 'asm' необъявленный (первое использование в этой функции)

Я получаю следующую ошибку во время компиляции:

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 ответа

Решение

Вы компилируете с опцией -std=c99,

Это отключает некоторые нестандартные расширения GCC, такие как asm особенность.

См. https://gcc.gnu.org/onlinedocs/gcc/C-Dialect-Options.html для некоторой (не очень точной) документации.

Удалить или изменить строку set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=c99") из вашего cmakefile, если вам нужна встроенная сборка.

Либо использовать __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:

-ansi и различные опции -std отключают определенные ключевые слова. Это вызывает проблемы, когда вы хотите использовать расширения GNU C или заголовочный файл общего назначения, который должен использоваться всеми программами, включая программы ISO C. Ключевые слова asm, typeof и inline недоступны в программах, скомпилированных с -ansi или -std (хотя inline можно использовать в программах, скомпилированных с -std=c99 или -std=c11). Ограничение по ключевому слову ISO C99 доступно только в том случае, если используется -std=gnu99 (который в конечном итоге будет использоваться по умолчанию) или -std=c99 (или эквивалентный -std=iso9899:1999) или опция для более поздней стандартной версии.

Способ решения этих проблем заключается в __ в начале и в конце каждого проблемного ключевого слова. Например, используйте __asm__ вместо асма и __inline__ вместо встроенного.

Другие компиляторы C не примут эти альтернативные ключевые слова; если вы хотите скомпилировать с другим компилятором, вы можете определить альтернативные ключевые слова как макросы, чтобы заменить их обычными ключевыми словами. Это выглядит так:

#ifndef __GNUC__
#define __asm__ asm
#endif

-pedantic и другие параметры вызывают предупреждения для многих расширений GNU C. Вы можете предотвратить такие предупреждения в одном выражении, написав __extension__ до выражения. __extension__ не имеет никакого эффекта, кроме этого.

-std=gnu99 позволяет расширения GNU, такие как asm, сохраняя при этом язык C99-like.

Стандарт C99

GCC работает так, чтобы соответствовать стандарту C99. Из проекта стандарта C99 N1256 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.

asm является расширением GCC, следовательно, вы не можете использовать с флагами, такими как std=c99 или же ansi

Более подробная информация на https://gcc.gnu.org/onlinedocs/gcc/C-Extensions.html

Другие вопросы по тегам