【问题标题】:asm keyword as identifier name in C?asm关键字作为C中的标识符名称?
【发布时间】:2018-12-11 20:29:31
【问题描述】:

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(\$$0) > $@)     \
                printf(\"$$F:%d: %s\\n\", NR, \$$0); \
        }" < $$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

【问题讨论】:

  • -std=c99 对于gcc 应该足够了(它适用于我)。你使用的是什么版本的gcc?你能显示cmakegcc的实际命令行吗?
  • 通过快速测试,gcc has no problem with this,而g++ is more picky about it(可能asm 是仅在C 中的保留关键字)。可能您的 cmake 甚至试图使用 g++ 来编译 C 文件?尝试使用make VERBOSE=1 来查看它正在调用哪些命令。
  • CMake 默认启用编译器扩展;您要的是 gnu99 模式,而不是 c99。有关如何关闭此功能以及设置要使用的 C 版本的正确方法,请参阅 cmake.org/cmake/help/latest/manual/…cmake.org/cmake/help/latest/prop_tgt/…cmake.org/cmake/help/latest/prop_tgt/…
  • @MatteoItalia:您的选项包括-std=c99,它选择标准C而不是GCC的默认值,在这种情况下会抱怨asm
  • @EricPostpischil:是的,他们包含它,因为 OP 将它包含在 Makefile 和 CMakeLists.txt 的标志中......

标签: c assembly makefile cmake keyword


【解决方案1】:

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

包含任何可能导致严格符合的扩展 程序变为无效会导致实现不合格。 此类扩展的示例是新关键字、额外的库函数 在标准头文件中声明,或名称为的预定义宏 不能以下划线开头。

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

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

附录

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

【讨论】:

    【解决方案2】:

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

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


    然而,它仍然是非常糟糕的风格,因为 C99、C11 和 C17 修订版确实将其称为common extension

    【讨论】:

    • @EricPostpischil 但它可能不会拒绝编译int main(int asm, char **argv) { } ...如果它接受int main(int argc, char **argv)至少不会拒绝
    • @EricPostpischil 该标准规定该实现应能够编译至少一个一切为真的程序。例如,在 MS-DOS 中,65535 字节的对象非常棘手……可能是程序实际上无法任何事情,因为所有数据段都用于那个对象。这并不意味着只能够编译一个程序就足够了。
    • 我不同意使用asm 作为标识符必然“非常糟糕的风格”。事实上,它可能是一种(不完美地)强制使用符合标准的 C 编译器编译代码的方法——类似于使用 int class; 强制使用 C 编译器而不是 C++ 编译器。 (恕我直言,不幸的是 gcc 在其默认模式下拒绝 int asm; 作为语法错误。)
    猜你喜欢
    • 2022-10-13
    • 1970-01-01
    • 2011-10-02
    • 2020-06-24
    • 1970-01-01
    • 2015-08-06
    • 2011-04-30
    相关资源
    最近更新 更多