Assembly 为什么是##&引用;在这里需要C宏,预处理MIPS程序集中的分号是什么意思?
我最近正在阅读基于MIPSfpga的嵌入式系统上运行的小操作系统的MIPS汇编 我有两个文件,Assembly 为什么是##&引用;在这里需要C宏,预处理MIPS程序集中的分号是什么意思?,assembly,mips,preprocessor,Assembly,Mips,Preprocessor,我最近正在阅读基于MIPSfpga的嵌入式系统上运行的小操作系统的MIPS汇编 我有两个文件,boot.S和boot.h。我使用命令mips sde elf gcc-c-o boot.o boot.S来编译它,这样它就可以通过c预处理器cpp 在文件boot.h中,它定义了一个宏: #define LEAF(name)\ .##text;\ .##globl name;\ .##ent name;\ name: ##是什么意思?我在info cpp导航到Macr
boot.S
和boot.h
。我使用命令mips sde elf gcc-c-o boot.o boot.S
来编译它,这样它就可以通过c预处理器cpp
在文件boot.h
中,它定义了一个宏:
#define LEAF(name)\
.##text;\
.##globl name;\
.##ent name;\
name:
##
是什么意思?我在info cpp
导航到Macros
,然后导航到Concatenation
,这称为“令牌粘贴或令牌连接”。但在这种情况下,我们为什么需要连接令牌呢?你看,boot.S
将通过cpp
,然后作为。但是as
也有一个内置的令牌解析器,所以我认为这里不需要粘贴令牌,因为as
将从cpp
的输出中将其解析为单个符号,而不是两个单独的符号cpp
无需费心粘贴它
然后,我使用命令gcc-eboot.S>boot.I
查看预处理后得到的结果。在boot.S
中,宏叶(\uu重置\u向量)
展开为以下内容:
.text; .globl __reset_vector; .ent __reset_vector;__reset_vector:
预处理的指令位于同一行。但是什么是代码>平均值?它没有作为
记录在信息中
##
是什么意思
从上一个和下一个标记中创建一个标记,并将它们粘贴在一起。此处的目的可能是防止预处理器在
和以下标识符之间插入额外的空间,因为CPP不会使用标识符解析
但是什么是代码>平均值
在大多数架构的GAS语法中,它是一个语句分隔符。汇编语句通常用换行符分隔,但是cpp
的宏无法轻松生成多行输出,因此需要另一个分隔符
在其他一些程序集语法(如NASM或MASM)中,
是注释字符
(根据您添加的内容进行了更新。)我仔细阅读了信息作为
。事实证明,GNU定义为
的“注释和语句”是特定于目标的。不同的汇编语言可能有不同的注释和语句语法,以及行分隔符。因此,我需要深入研究MIPS语法。据我所知,
CPP操作符不是必需的,也没有任何效果,除非text
、globl
或ent
都是,将d定义为宏
#define LEAF(name)\
.##text;\
.##globl name;\
.##ent name;\
name:
LEAF(myname)
CPP输出:.text。globl myname。我的名字;myname:
#define LEAF2(name)\
.text;\
.globl name;\
.ent name;\
name:
LEAF2(myname)
CPP输出:.text。globl myname。我的名字;myname:
#define LEAF2(name)\
.text;\
.globl name;\
.ent name;\
name:
LEAF2(myname)
输出与##
标记粘贴相同或不相同。
是此asm语法中的语句分隔符(如换行符),因此此宏将切换到.text
部分,并以宏arg作为名称声明一个全局符号。那里还有一个.ent name
指令,我不知道它是做什么的。可能是@LưuVĩnhPhúc的重复,谢谢。我读了那篇文章,它没有被复制。我在想为什么这里需要##
,而不是##
的语法含义。至于“###”,我想这只是一个双重保险箱。嗯。。。不确定。我可以想到一个挑剔的预处理器,它将
从其输出中的以下标识符中分离出来,这将破坏构造。另一方面,.text
作为##
操作符的结果也不是严格符合的(C标准要求它是一个C令牌,但事实并非如此),因此它也不能完全安全地避免额外挑剔的预处理器。@Han##
是令牌粘贴操作符。它将前后出现的内容连接成一个标记。这里不起作用,例如。text
在C编程语言中不是有效的标记。@AntoineL@fuz是的,我还假设cpp
会检查符号是否是有效的C样式标识符。然而,我做了一个小测试,#define foo.var=1;printf(“%d\n”,.var)
,当我使用命令gcc-efoo.c>foo.I
对其进行预处理(展开宏foo
)时,cpp
没有抱怨.var
是无效标识符。但是当我编译它时,gcc
编译器对此抱怨并启动了一个错误。@fuz@AntoineL此外,根据info-cpp
然后导航到Tokenization
,它说“编译器不会重新标记预处理器的输出。每个预处理标记都成为一个编译器标记。”。这就是我们编译.c
文件时发生的情况<代码>gcc
是前端。但是当我们使用gcc编译.S
文件时,gcc使用as
来编译它。但是没有记录as
是否将重新标记。Ok。我想我在这里太迂腐了。也许在这里查看##
可以防止意外的令牌解析结果,这样做是合理的,并且可以避免深入了解cpp
实现细节。如果使用.globl
而不使用#
,cpp将不会插入
。这很奇怪,也没有必要,除非你在这之前定义了entfoobar。