这是一个简短的文档,描述了linux内核的首选编码风格。编码风格非常个人化,我不会强迫我对任何人的观点,但这是我必须能够维护的任何东西,而且我更喜欢它用于其他大多数事情。请至少考虑这里提出的观点。
首先,我建议打印出GNU编码标准的副本, 而不是阅读它。烧掉它们,这是一个伟大的象征性姿态。
无论如何,这里是:
第1章:缩进
标签为8个字符,因此缩进也是8个字符。 有些异端运动试图将缩进4(甚至2!)个字符深入,这类似于试图将PI的值定义为3。
理由:缩进背后的整个想法是明确定义在哪里
一个控制块开始和结束。特别是当你一直在寻找
在你的屏幕上连续20个小时,你会发现它更容易看到
如果你有大的缩进,缩进如何工作。
现在,有些人会声称有8个字符的缩进会使 代码向右移动太远,并且难以在80个字符的终端屏幕上阅读。答案是,如果你需要超过3个级别的缩进,你仍然会被搞砸,并且应该修复你的程序。
简而言之,8-char缩进使事情更容易阅读,并且当你将函数嵌套得太深时,还有一个额外的 好处就是警告你。注意那个警告。
在switch语句中缓和多个缩进级别的首选方法是 将“switch”及其下级“case”标签对齐在同一列而不是双缩进“case”标签。例如:
switch (suffix) {
case ‘G’:
case ‘g’:
mem <<= 30;
break;
case ‘M’:
case ‘m’:
mem <<= 20;
break;
case ‘K’:
case ‘k’:
mem <<= 10;
/* fall through */
default:
break;
}
除非您有隐藏的内容,否则不要在一行中放置多个语句 :
//counter-example
if (condition) do_this;
do_something_everytime;
不要在一行上放置多个作业。内核编码风格 非常简单。避免棘手的表达。
除了注释,文档和Kconfig之外,空格永远不会 用于缩进,上面的示例是故意破坏的。
得到一个体面的编辑器,不要在行尾留下空白。
第2章:打破长行和字符串
编码风格是关于使用常用工具的可读性和可维护性 。
线条长度的限制是80列,这是一个非常 优选的限制。
超过80列的语句将被分解为合理的块,除非 超过80列显着提高可读性并且不隐藏信息。后代总是比父母短得多,并且基本上放在右边。这同样适用于具有长参数列表的函数头。但是,永远不要破坏用户可见的字符串,例如printk消息,因为这会破坏grep的能力。
第3章:放置大括号和空格
C样式中总是出现的另一个问题是大括号的位置 。与缩进尺寸不同,选择一种放置策略的技术原因很少,但是先知Kernighan和Ritchie向我们展示的首选方法是将开口支撑放在最后一行,然后关闭先支撑,因此:
if (x is true) {
we do y
}
这适用于所有非函数语句块(if,switch,for, while,do)。 例如:
switch (action) {
case KOBJ_ADD:
return “add”;
case KOBJ_REMOVE:
return “remove”;
case KOBJ_CHANGE:
return “change”;
default:
return NULL;
}
但是,有一个特例,即函数:它们在下一行的开头有 开括号,因此:
int function(int x)
{
body of function
}
世界各地的异教徒都声称这种不一致 是…好吧…不一致,但是所有正确思考的人都知道(a)K&R是_right_和(b)K&R是对的。此外,函数无论如何都是特殊的(你不能将它们嵌套在C中)。
请注意,右括号中的右括号是__, 在后面跟着相同语句的延续的情况下,即do语句中的“while”或if语句中的“else” , 像这样:
do {
body of do-loop
} while (condition);
和
if (x == y) {
…
} else if (x > y) {
…
} else {
…
}
理由:K&R。
另外,请注意,此支撑位置还可以最大限度地减少空 (或几乎为空)线的数量,而不会降低可读性。因此,由于屏幕上新线的供应不是可再生资源(想想这里的25行终端屏幕),您可以有更多空行来发表评论。
不要在单个语句所做的情况下不必要地使用大括号。
if (condition)
action();
和
if (condition)
do_this();
else
do_that();
如果条件语句的只有一个分支是单个语句,则不适用 ; 在后一种情况下,在两个分支中使用大括号:
if (condition) {
do_this();
do_that();
} else {
otherwise();
}
3.1:空间
使用空间的Linux内核样式(主要)取决于 函数与关键字的使用。在(大多数)关键字之后使用空格。值得注意的例外是sizeof,typeof,alignof和__attribute__,它们看起来有点像函数(并且通常与Linux中的括号一起使用,尽管它们在语言中不是必需的,例如:“struct fileinfo”之后的“sizeof info”; “宣布)。
所以在这些关键字之后使用空格:
if,switch,case,for,do,while
for (i = 10; i <= 10; i++){
…
}
但不是sizeof,typeof,alignof或__attribute__ 。例如,
s = sizeof(struct file);
不要在带括号的表达式周围(内部)添加空格。这个例子是 坏:
//counter-example
s = sizeof( struct file );
声明指针数据或返回指针类型的函数时, 首选使用’ * '与数据名称或函数名称相邻,而不是与类型名称相邻。例子:
char *linux_banner;
unsigned long long memparse(char *ptr, char **retptr);
char *match_strdup(substring_t *s);
在大多数二进制和三元运算符周围(在每一侧)使用一个空格, 例如以下任何一个:
= + - <> * /%| &^ <=> = ==!=?:
if (x <= 100 || x > 10){
…
}
但是在一元运算符之后没有空格:
&* + - 〜!sizeof typeof alignof __attribute__已定义
s = sizeof(struct file);
在后缀增加和减少一元运算符之前没有空格:
++ -
前缀增加和减少一元运算符后没有空格:
++ -
for (i = 10; i <= 10; i++){
…
}
'周围没有空间。'和“ - > ”结构成员运营商。
stu->name = “Yangbingxue”;
Domain Premium: stu.id = 120171080212;
不要在行的末尾留下尾随空格。一些具有“智能”缩进的编辑器 会在新行的开头插入空格,因此您可以立即开始键入下一行代码。但是,如果您最终没有在那里放置一行代码,某些此类编辑器不会删除空格,例如,如果您留下一个空行。因此,您最终会得到包含尾随空格的行。
Git会警告你有关引入尾随空格的补丁,并且可以 选择为你删除尾随空格; 但是,如果应用一系列补丁,这可能会使系列中的后续补丁因更改其上下文行而失败。
第4章:命名
C是斯巴达语言,您的命名也应如此。与Modula-2 和Pascal程序员不同,C程序员不使用像“ThisVariableIsATemporaryCounter”这样的可爱名称。AC程序员会将变量称为“tmp”,这样更容易编写,而且难以理解。
但是,虽然混合大小写的名称不受欢迎,但全局变量的描述性名称 是必须的。调用全局函数“foo”是一种射击攻击。
GLOBAL变量(仅在您需要它们时才使用)需要 具有描述性名称,全局函数也是如此。如果你有一个计算活动用户数的函数,你应该调用“count_active_users()”或类似的函数,你应该_not_称之为“cntusr()”。
将函数类型编码到名称中(所谓的匈牙利 表示法)是脑损坏的 - 编译器无论如何都知道类型并且可以检查它们,它只会使程序员感到困惑。难怪MicroSoft制作有缺陷的程序。
LOCAL变量名称应该简短,并且要点。如果你有 一些随机整数循环计数器,它应该被称为“i”。如果没有机会被误解,那么称它为“loop_counter”是非生产性的。类似地,“tmp”可以是用于保存临时值的任何类型的变量。
如果你害怕混淆你的本地变量名,你还有另一个 问题,就是所谓的功能 - 生长 - 激素 - 失衡综合症。见第6章(功能)。
第5章:Typedef
请不要使用“vps_t”之类的东西。
对结构和指针使用typedef是一个_mistake_。当你看到一个
//counter-example
vps_t a;
在源头,这是什么意思?
相反,如果它说
struct virtual_container *a;
你实际上可以告诉“a”是什么。
很多人认为typedef“有助于提高可读性”。不是这样。他们是
仅适用于:
(a)完全不透明的对象(其中typedef主动用于_hide_ 对象是什么)。
示例:“pte_t”等不透明对象,您只能使用正确的访问器函数进行访问 。
注意!不透明和“访问者功能”本身并不好。
我们将它们用于pte_t之类的原因就是那里
真的绝对是_zero_便携式信息。
(b)清除整数类型,其中抽象_helps_避免混淆 它是“int”还是“long”。
u8 / u16 / u32是完美的typedef,虽然它们 比(d)更适合这里。
注意!再次 - 需要一个_reason_为此。如果是的话
“unsigned long”,那么没有理由这样做
typedef unsigned long myflags_t;
但是如果有明确的理由说明为什么它在某些情况下 可能是“unsigned int”并且在其他配置下可能是“unsigned long”,那么一定要继续使用typedef。
(c)当你使用sparse从字面上创建一个_new_类型进行 类型检查时。
(d)在某些特殊情况下与标准C99类型相同的新类型 。
虽然只需要很短的时间让眼睛和 大脑习惯于像’uint32_t’这样的标准类型,但有些人反对使用它们。
因此,允许使用特定于Linux的“u8 / u16 / u32 / u64”类型及其与标准类型相同的 签名等效项 - 尽管它们在您自己的新代码中不是必需的。
编辑已使用一个或另一组 类型的现有代码时,应该符合该代码中的现有选项。
(e)在用户空间中安全使用的类型。
在用户空间可见的某些结构中,我们不能 要求C99类型,也不能使用上面的“u32”形式。因此,我们在与用户空间共享的所有结构中使用__u32和类似的类型。
也许还有其他情况,但规则应该基本上是永远不要 使用typedef,除非你能清楚地匹配其中一个规则。
通常,指针或具有可以合理直接访问的元素的结构 应该_never_是typedef。
第6章:功能
功能应该简短而甜蜜,只做一件事。它们应该 适合一两个屏幕文本(ISO / ANSI屏幕大小为80x24,我们都知道),做一件事并做得很好。
函数的最大长度与该函数的复杂度和缩进级别成反比 。所以,如果你有一个概念上简单的函数,它只是一个很长(但很简单)的case语句,你需要为很多不同的情况做很多小事,那么拥有更长的函数是可以的。
但是,如果你有一个复杂的功能,并且你怀疑一个 不太优秀的一年级高中生可能甚至不了解这个功能的全部内容,那么你应该更加严格地遵守最大限度。使用具有描述性名称的辅助函数(如果您认为它对性能至关重要,您可以要求编译器对它们进行内联,并且它可能比您所做的更好)。
函数的另一个度量是局部变量的数量。 他们 不应该超过5-10,否则你做错了什么。重新考虑功能,并将其拆分成更小的部分。人类的大脑通常可以轻松地跟踪大约7种不同的东西,更多的东西,它会混淆。你知道你很聪明,但也许你想了解你在2周后所做的事情。
在源文件中,使用一个空行分隔功能。如果导出该函数 ,则它的EXPORT *宏应该在关闭函数括号行之后立即执行。例如:
int example(void)
{
…
}
int system_is_up(void)
{
return system_state == SYSTEM_RUNNING;
}
EXPORT_SYMBOL(system_is_up);
在函数原型中,包含参数名称及其数据类型。尽管C语言不需要这样做,但在Linux中它是首选,因为它是为读者添加有价值信息的简单方法。
第7章:集中退出职能
虽然有些人不赞成使用,但编译器经常以无条件跳转指令的形式使用等效的goto语句 。
当函数从多个位置退出并且必须完成一些常见工作(如清理)时,goto语句会派上用场 。
理由是:
无条件陈述更容易理解和遵循
减少了筑巢
防止在进行修改时不更新单个退出点的错误
保存编译器工作以优化冗余代码;)
int fun(int a)
{
int result = 0;
char *buffer = kmalloc(SIZE);
if (buffer == NULL)
return -ENOMEM;
if (condition1) {
while (loop1) {
…
}
result = 1;
goto out;
}
…
out:
kfree(buffer);
return result;
}
第8章:评论
评论很好,但也有过度评论的危险。 永远不要 试图解释你的代码如何在注释中工作:编写代码以便_working_是显而易见的更好,并且解释编写错误的代码是浪费时间。
通常,您希望您的注释告诉您代码的作用,而不是如何。 另外,尽量避免在函数体中放置注释:如果函数太复杂而需要单独注释它的一部分,那么你应该回到第6章一段时间。你可以做一些小评论来记录或警告某些特别聪明(或丑陋),但尽量避免过多。相反,将评论放在函数的头部,告诉人们它做了什么,并可能为什么这样做。
在评论内核API函数时,请使用kernel-doc格式。 有关详细信息,请参阅文档Documentation / kernel-doc-nano-HOWTO.txt和scripts / kernel-doc 。
评论的Linux风格是C89“/ * … * /”风格。
不要使用C99风格的“// …”注释。
长(多行)注释的首选样式是:
/*
This is the preferred style for multi-line
comments in the Linux kernel source code.
Please use it consistently.
Description: A column of asterisks on the left side,
with beginning and ending almost-blank lines.
*/
对于net / 和drivers / net /中的文件,长(多行)注释的首选样式 有点不同。
/* The preferred comment style for files in net/ and drivers/net
looks like this.
It is nearly the same as the generally preferred comment style,
but there is no initial almost-blank line.
*/
对数据进行评论也很重要,无论它们是基本类型还是派生类型。为此,每行只使用一个数据声明(多个数据声明没有逗号)。这使您有空间对每个项目进行小评论,并解释其用途。
第9章:你弄得一团糟
没关系,我们都这样做。您的长期Unix 用户助手可能已经告诉您 “GNU emacs”会自动为您设置C源代码,并且您已经注意到它是,它确实这样做了,但它使用的默认值不太理想(事实上,它们比随机输入更糟糕 - 无数的猴子输入GNU emacs永远不会成为一个好的程序。
因此,您可以删除GNU emacs,或者将其更改为使用saner 值。要执行后者,您可以在.emacs文件中添加以下内容:
(defun c-lineup-arglist-tabs-only (ignored)
“Line up argument lists by tabs, not spaces”
(let* ((anchor (c-langelem-pos c-syntactic-element))
(column (c-langelem-2nd-pos c-syntactic-element))
(offset (- (1+ column) anchor))
(steps (floor offset c-basic-offset)))
(* (max steps 1)
c-basic-offset)))
(add-hook 'c-mode-common-hook
(lambda ()
;; Add kernel style
(c-add-style
“linux-tabs-only”
'(“linux” (c-offsets-alist
(arglist-cont-nonempty
c-lineup-gcc-asm-reg
c-lineup-arglist-tabs-only))))))
(add-hook 'c-mode-hook
(lambda ()
(let ((filename (buffer-file-name)))
;; Enable kernel mode for the appropriate files
(when (and filename
(string-match (expand-file-name “~/src/linux-trees”)
filename))
(setq indent-tabs-mode t)
(c-set-style “linux-tabs-only”)))))
这将使emacs在〜/ src / linux-trees 下面的C文件的内核编码样式变得更好。
但即使你没有让emacs做出理智的格式化,也不会 丢失所有内容:使用“缩进”。
现在,再一次,GNU缩进具有与GNU emacs相同的脑死设置 ,这就是为什么你需要给它一些命令行选项。
然而,这并不是太糟糕,因为即使是GNU缩进的制作者也 认识到K&R的权威(GNU人不是邪恶的,他们在这个问题上只是被严重误导),所以你只需给缩进选项“-kr -i8 “(代表”K&R,8个字符缩进“),或使用”scripts / Lindent“,这些缩进采用最新款式。
“indent”有很多选项,特别是在评论 重新格式化时,您可能需要查看手册页。但请记住:“缩进”并不能解决糟糕的编程问题。
第10章:Kconfig配置文件
对于源树中的所有Kconfig *配置文件, 缩进有些不同。“config”定义下的行使用一个选项卡缩进,而帮助文本则缩进另外两个空格。例:
config AUDIT
bool “Auditing support”
depends on NET
help
Enable auditing infrastructure that can be used with another
kernel subsystem, such as SELinux (which requires this for
logging of avc messages output). Does not do system-call
auditing without CONFIG_AUDITSYSCALL.
严重危险的功能(例如对某些文件系统的写支持 )应在其提示字符串中突出显示:
config ADFS_FS_RW
bool “ADFS write support (DANGEROUS)”
depends on ADFS_FS
…
有关配置文件的完整文档,请参阅 Documentation / kbuild / kconfig-language.txt文件。
第11章:数据结构
在创建和销毁它们的单线程环境之外具有可见性的数据结构应始终具有引用计数。在内核中,垃圾收集不存在(并且在内核垃圾收集之外是缓慢且低效的),这意味着你绝对_have_引用计数所有用途。
引用计数意味着您可以避免锁定,并允许多个 用户并行访问数据结构 - 而不必担心结构突然离开它们只是因为他们睡了一会儿或做了一些其他事情。
请注意,锁定不是引用计数的替代。 锁定用于保持数据结构的一致性,而引用计数是一种内存管理技术。通常两者都是必需的,不要相互混淆。
当存在不同“类”的用户时,许多数据结构确实可以具有两个级别的引用计数 。子类计数计算子类用户的数量,并在子类计数变为零时仅减少一次全局计数。
这种“多级引用计数”的示例可以在 内存管理(“struct mm_struct”:mm_users和mm_count)和文件系统代码(“struct super_block”:s_count和s_active)中找到。
记住:如果另一个线程可以找到您的数据结构,
并且你没有 参考计数,
你几乎肯定有一个bug。
第12章:宏,枚举和RTL
定义枚举中的常量和标签的宏的名称是大写的。
#define CONSTANT 0x12345
在定义几个相关常量时,首选枚举。
CAPITALIZED宏名称受到赞赏,但宏类似于函数
可以小写命名。
通常,内联函数优于类似函数的宏。
具有多个语句的宏应该包含在do-while块中:
#define macrofun(a, b, c) \
do { \
if (a == 5) \
do_this(b, c); \
} while (0)
使用宏时要避免的事项:
1)影响控制流程的宏:
//counter-example
#define FOO(x) \
do { \
if (blah(x) < 0) \
return -EBUGGERED; \
} while(0)
是个坏主意。它看起来像一个函数调用但退出“调用” 函数; 不要破坏那些将读取代码的人的内部解析器。
2)依赖于具有魔术名称的局部变量的宏:
#define FOO(val) bar(index, val)
可能看起来像是一件好事,但当人们阅读代码并且很容易因看似无辜的变化而破裂时,它会让人感到困惑。
3)带有用作l值的参数的宏:FOO(x)= y; 如果某人例如将FOO转换为内联函数,则会 咬你。
4)忘记优先级:使用表达式定义常量的宏 必须将表达式括在括号中。请注意使用参数的宏的类似问题。
#define CONSTANT 0x4000
#define CONSTEXP (CONSTANT | 3)
cpp手册详尽地讨论了宏。gcc内部手册还 介绍了RTL(寄存器传输语言),它在内核中经常与汇编语言一起使用。
第13章:打印内核消息
内核开发人员喜欢被视为有文化。注意内核消息的拼写 以给人留下好印象。不要使用像“不要”这样残缺的词; 改为使用“不要”或“不要”。使消息简洁,清晰,明确。
内核消息不必以句点终止。
在括号中打印数字(%d)不会增加值,应该避免。
您应该使用
提供良好的调试信息可能是一个很大的挑战; 一旦 你拥有它们,它们可以为远程故障排除提供巨大帮助。当未定义DEBUG符号时(即,默认情况下不包括它们),应编译此类消息。当你使用dev_dbg()或pr_debug()时,这是自动的。许多子系统都有Kconfig选项来打开-DDEBUG。
相关约定使用VERBOSE_DEBUG将dev_vdbg()消息添加到已由DEBUG启用的消息。
第14章:分配内存
内核提供以下通用内存分配器:
kmalloc(),kzalloc(),kmalloc_array(),kcalloc(),vmalloc()和 vzalloc()。有关它们的更多信息,请参阅API文档 。
传递结构大小的首选形式如下:
p = kmalloc(sizeof(*p), …);
结构名称拼写出来的替代形式会损害可读性,并且 当指针变量类型发生更改但传递给内存分配器的相应sizeof不是时,会引发错误。
转换返回值是一个空指针是多余的。C编程语言保证从void指针到任何其他指针类型的转换 。
分配数组的首选形式如下:
p = kmalloc_array(n, sizeof(…), …);
分配归零阵列的首选形式如下:
p = kcalloc(n, sizeof(…), …);
两种形式都检查分配大小n * sizeof(…)上的溢出,
如果发生,则返回NULL。
第15章:内联疾病
似乎有一种常见的误解,即gcc有一个神奇的“让我 更快”的加速选项称为“内联”。虽然使用内联可能是合适的(例如,作为替换宏的一种方法,请参阅第12章),但通常不是。大量使用内联关键字会导致更大的内核,从而导致整个系统整体运行速度变慢,因为CPU的icache占用空间更大,而且因为页面缓存的可用内存更少。考虑一下; 页面缓存未命中导致磁盘搜索,这很容易花费5毫秒。有很多cpu周期可以进入这5毫秒。
一个合理的经验法则是不要将内联函数放在其中包含超过3行代码的函数 中。这个规则的一个例外是已知参数是一个编译时常量的情况,并且由于这个常量,你知道编译器将能够在编译时优化你的大部分函数。有关后一种情况的一个很好的示例,请参阅kmalloc()内联函数。
通常人们争辩说,将内联添加到静态且仅使用 一次的函数总是一个胜利,因为没有空间权衡。虽然这在技术上是正确的,但gcc能够在没有帮助的情况下自动内联这些内容,并且当第二个用户出现时删除内联的维护问题超过了告诉gcc无论如何都要做的事情的暗示的潜在价值。
第16章:函数返回值和名称
函数可以返回许多不同类型的值,其中一个 最常见的是指示函数是成功还是失败的值。这样的值可以表示为错误代码整数(-Exxx =失败,0 =成功)或“成功”布尔值(0 =失败,非零=成功)。
混合这两种表示形式是难以发现的错误的肥沃来源 。如果C语言包含整数和布尔值之间的强烈区分,那么编译器会为我们发现这些错误…但事实并非如此。为了帮助防止此类错误,请始终遵循以下约定:
如果函数的名称是操作或命令性命令,
该函数应返回错误代码整数。如果名字
是一个谓词,该函数应该返回一个“成功”的布尔值。
例如,“add work”是一个命令,add_work()函数返回0 表示成功,或者-EBUSY表示失败。同样,“PCI device present”是 谓词,如果成功找到匹配的设备,则pci_dev_present()函数返回1,否则返回 0。
所有EXPORTed函数都必须遵守此约定,所有公共函数也应如此 。私有(静态)功能不需要,但 建议他们这样做。
返回值是计算的实际结果而不是计算是否成功的指示的函数 不受此规则的约束 。通常它们通过返回一些超出范围的结果来指示失败 。典型的例子是返回指针的函数; 他们使用 NULL或ERR_PTR机制来报告失败。
第17章:不要重新发明内核宏
头文件include / linux / kernel.h包含许多你应该使用的宏 ,而不是自己明确地编写它们的一些变体。 例如,如果需要计算数组的长度,请利用 宏
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
同样,如果需要计算某些结构成员的大小,请使用
#define FIELD_SIZEOF(t, f) (sizeof(((t*)0)->f))
如果需要,还有min()和max()宏可以进行严格的类型检查 。请仔细阅读该头文件,看看还有哪些已 定义,您不应该在代码中重现。
第18章:编辑模特和其他琐事
一些编辑器可以解释嵌入在源文件中的配置信息, 用特殊标记表示。例如,emacs解释标记为这样的行 :
-- mode: c --
或者像这样:
/*
Local Variables:
compile-command: “gcc -DMAGIC_DEBUG_FLAG foo.c”
End:
*/
Vim解释看起来像这样的标记:
/* vim:set sw=8 noet */
不要在源文件中包含任何这些内容。人们有自己的个人 编辑器配置,源文件不应该覆盖它们。这 包括缩进和模式配置的标记。人们可以使用他们 自己的自定义模式,或者可能有其他一些神奇的方法来使缩进 正常工作。
第19章:内联汇编
在特定于体系结构的代码中,您可能需要使用内联汇编来与CPU或平台功能进行交互 。必要时请不要犹豫。 但是,当C可以完成工作时,不要无偿使用内联汇编。你可以 而且应该在可能的情况下从C中拨打硬件。
考虑编写简单的辅助函数来包装内联汇编的常见位 ,而不是重复编写它们。请记住 ,内联汇编可以使用C参数。
大型,非平凡的汇编函数应该放在.S文件中,并在C头文件中定义相应的 C原型。汇编函数的C原型 应使用“asmlinkage”。
您可能需要将asm语句标记为volatile,以防止GCC 在GCC未发现任何副作用时将其删除。但是,您并不总是需 要这样做,并且不必要地这样做会限制优化。
当编写包含多个指令的单个内联汇编语句时 ,将每个指令放在单独的带引号的字符串中的单独行上 ,并使用\ n \ t结束除最后一个字符串以外的每个字符串以正确缩进汇编输出中的 下一条指令:
asm (“magic %reg1, #42\n\t”
附录I:参考文献
C编程语言,第二版
作者:Brian W. Kernighan和Dennis M. Ritchie。
Prentice Hall,Inc.,1988。
国际标准书号0-13-110362-8(平装本),0-13-110370-9(精装本)。
网址:http://cm.bell-labs.com/cm/cs/cbook/
编程实践
作者:Brian W. Kernighan和Rob Pike。
Addison-Wesley,Inc.,1999。
国际标准书号0-201-61586-X。
网址:http://cm.bell-labs.com/cm/cs/tpop/
GNU手册 - 符合K&R和本文的内容 - 适用于cpp,gcc,
gcc内部和缩进,全部可从http://www.gnu.org/manual/获得