asm 关键字作为 C 中的标识符名称?

asm keyword as identifier name in C?

I've seen a project 使用 asm 关键字作为变量名,并且代码可以使用 Linux:

上提供的 Makefile 正常编译
int
main(int ac, char *av[])
{
    struct TMap *tm;
    FILE *inf, *hf;
    char *f, *sep;
    int c, asm; // <---

    asm = Defasm;
    // ...
}

这里是完整的 Makefile:

BIN = qbe

V = @
OBJDIR = obj

SRC      = main.c util.c parse.c cfg.c mem.c ssa.c alias.c load.c copy.c \
           fold.c live.c spill.c rega.c gas.c
AMD64SRC = amd64/targ.c amd64/sysv.c amd64/isel.c amd64/emit.c
ARM64SRC = arm64/targ.c arm64/abi.c arm64/isel.c arm64/emit.c
SRCALL   = $(SRC) $(AMD64SRC) $(ARM64SRC)

AMD64OBJ = $(AMD64SRC:%.c=$(OBJDIR)/%.o)
ARM64OBJ = $(ARM64SRC:%.c=$(OBJDIR)/%.o)
OBJ      = $(SRC:%.c=$(OBJDIR)/%.o) $(AMD64OBJ) $(ARM64OBJ)

CFLAGS += -Wall -Wextra -std=c99 -g -pedantic

$(OBJDIR)/$(BIN): $(OBJ) $(OBJDIR)/timestamp
    @test -z "$(V)" || echo "ld $@"
    $(V)$(CC) $(LDFLAGS) $(OBJ) -o $@

$(OBJDIR)/%.o: %.c $(OBJDIR)/timestamp
    @test -z "$(V)" || echo "cc $<"
    $(V)$(CC) $(CFLAGS) -c $< -o $@

$(OBJDIR)/timestamp:
    @mkdir -p $(OBJDIR)
    @mkdir -p $(OBJDIR)/amd64
    @mkdir -p $(OBJDIR)/arm64
    @touch $@

$(OBJ): all.h ops.h
$(AMD64OBJ): amd64/all.h
$(ARM64OBJ): arm64/all.h
obj/main.o: config.h

config.h:
    @case `uname` in                               \
    *Darwin*)                                      \
        echo "#define Defasm Gasmacho";        \
        echo "#define Deftgt T_amd64_sysv";    \
        ;;                                     \
    *)                                             \
        echo "#define Defasm Gaself";          \
        case `uname -m` in                     \
        *aarch64*)                             \
            echo "$define Deftgt T_arm64"; \
            ;;                             \
        *)                                     \
            echo "#define Deftgt T_amd64_sysv";\
            ;;                             \
        esac                                   \
        ;;                                     \
    esac > $@

install: $(OBJDIR)/$(BIN)
    mkdir -p "$(DESTDIR)/$(PREFIX)/bin/"
    cp $< "$(DESTDIR)/$(PREFIX)/bin/"

uninstall:
    rm -f "$(DESTDIR)/$(PREFIX)/bin/$(BIN)"

clean:
    rm -fr $(OBJDIR)

clean-gen: clean
    rm -f config.h

check: $(OBJDIR)/$(BIN)
    tools/test.sh all

check-arm64: $(OBJDIR)/$(BIN)
    TARGET=arm64 tools/test.sh all

src:
    @echo $(SRCALL)

80:
    @for F in $(SRCALL);                       \
    do                                         \
        awk "{                             \
            gsub(/\t/, \"        \"); \
            if (length($[=11=]) > $@)     \
                printf(\"$$F:%d: %s\n\", NR, $[=11=]); \
        }" < $$F;                          \
    done

.PHONY: clean clean-gen check check-arm64 src 80 install uninstall

我想知道如何实现编译器将允许 asm 作为变量名(忽略这样做是不好的风格这一事实)。我尝试将 Makefile 移植到 CMakeLists.txt,但由于 asm 的无效使用,编译器抛出了错误。如何在不更改代码的情况下解决此问题?我已经像 Makefile 那样强制使用 C99 标准并使用了相同的 C 编译器标志,但这没有帮助:

cmake_minimum_required(VERSION 3.10.2)
project(qbe C)

set(CMAKE_C_STANDARD 99)
set(CMAKE_C_FLAGS "-Wall -Wextra -std=c99 -g -pedantic")

include_directories(amd64)

add_executable(qbe
        amd64/all.h
        amd64/emit.c
        amd64/isel.c
        amd64/sysv.c
        amd64/targ.c
        alias.c
        all.h
        cfg.c
        copy.c
        fold.c
        gas.c
        live.c
        load.c
        main.c
        mem.c
        ops.h
        parse.c
        rega.c
        spill.c
        ssa.c
        util.c)

由于 IDE 支持,我想使用 CMake

asm 不是标准的 C 关键字。符合标准的 C 编译器可能不会拒绝编译使用 asm 作为标识符的程序。

使用 -std=c99 明确选择标准也将删除 asm 关键字。但是,您可以继续使用 __asm__,因为所有以两个下划线开头的名称始终由实现保留以供 any 使用。


但是,还是非常糟糕的风格,因为C99,C11和C17的修订do 将其作为 common extension 提及。

asm 不是 标准 C 的关键字,也不是保留标识符,但 the standard recognizes it as a common extension。该标准还指出

The inclusion of any extension that may cause a strictly conforming program to become invalid renders an implementation nonconforming. Examples of such extensions are new keywords, extra library functions declared in standard headers, or predefined macros with names that do not begin with an underscore.

这在Annex J中,是非规范性的,但它只是总结了一个可以从规范性文本中得出的结论。因此,符合规范的实现不会拒绝使用 asm 作为标识符的代码。

例如,我发现 GCC 在使用它支持的任何严格一致性模式(-std=c89-std=c99-std=c11),但默认情况下会以错误或特别启用的 GNU 扩展(例如 -std=gnu11)拒绝它。如果您使用的是不同的编译器,那么您将需要查阅其文档以了解如何获得与该领域标准的一致性,如果确实可以这样做的话。

附录

至于为什么您的 CMake 尝试失败,CMAKE_C_STANDARD 属性 并没有像您认为的那样做。它告诉 CMake 如果可能的话,选择提供指定版本 C 标准的特性的编译器选项,但它不要求 严格符合 该标准。文档明确假设它会导致在某些情况下使用 -std=gnu11 选项,并且该选项或类似的包含选项会产生与您想要的相反的效果。