这就像一种分割方式"+r"(value)
将输入/输出操作数转换为单独的操作数(具有单独的 C 变量)以用于输入和输出,同时仍然强制它们选择相同的寄存器。
具体来说"0"
表示“在与操作数 0 相同的寄存器中输入操作数”,在本例中为"=r"(value)
。所以无论注册什么%0
picks, %1
将是相同的寄存器。操作数从左到右计数,从0
.操作数的编号相同%0
, %1
当匹配约束引用较早的操作数时,asm 模板中的 等适用。
我只见过它与匹配输出约束的输入约束一起使用。这使您可以从模板中省略它,而不会有编译器期望您的 asm 模板从一个寄存器复制到另一个寄存器的风险。
对输入和输出使用相同的 C 变量更容易"+r"(value)
.对此的匹配约束是毫无意义的复杂性。
Maybe "+r"
仅在更高版本的 gcc 中添加,因为您确实会看到当读/写操作数更容易时使用匹配约束。
如果在同一个选项中数字与字母一起使用,则数字应放在最后。”
这是考虑给编译器提供多个约束选择的约束的可能性。例如"rm"
让编译器选择寄存器或内存。
"a0"
在 x86 上会选择 EAX 或相同的寄存器作为操作数0
。我不确定什么时候会有用。也许它可以与早期破坏器一起使用,告诉编译器该输入与某个输出位于同一寄存器中仍然可以吗?但可选任何寄存器,例如"r0"
?
显然如果你使用像这样的约束"r0"
你(通常)需要明确使用%1
(或者它具有的任何数字或命名操作数)位于 asm 模板中,因为您不知道编译器将在给定周围代码和优化级别的情况下选择哪个位置。
调试约束时,使用包含约束的 asm 注释会很有用,包括您要做出假设的内容。
asm ("swap %0 # other operand: %1 " : "=r"(output) : "0"(input));
生成的 asm 将打印相同的寄存器名称两次%0
and %1
。这个案例很简单;在更复杂的情况下它会变得更有趣。
就像如果你用过"r"(input)
,您的代码可能会正常工作,因为编译器确实为输入和输出选择了相同的reg(因为没有早期破坏)。但是当它因为选择了不同的规则而崩溃时output
(并期望原始值input
仍然在其寄存器中不变),您可以通过查看约束选择的寄存器来调试它,然后意识到您假设它们会选择相同的寄存器但没有告诉编译器。