visualstudio内联程序集发出字符串宏
visual studio inline assembly emit string macro
是否有用于内联汇编的宏使用__emit
关键字将C字符串作为字节序列发出?
例如,要发出"Hello",您必须编写
__emit 'H'
__emit 'e'
__emit 'l'
__emit 'l'
__emit '0'
__emit 0x0
有人知道有一个宏可以只写EMIT_MACRO("Hello")
吗?
TL;DR:不可能。
等一下,还不是所有的都失去了。在前面,这里有一个你可以实现的预告片:EMIT_STRING(H,e,l,l,o,!)
但让我先扩展一下引言中的直率语句:对序列中的每个元素执行操作需要某种迭代或递归。无论哪种方式,您都需要一个终止条件来很好地终止扩展。虽然可以通过延迟扩展获得递归宏,但没有办法告诉预处理器何时停止(需要引用;请随时贡献)。
那么,这就排除了字符串文字的使用。这给开发人员带来了将字符串文字拆分为一系列字符文字的负担。不幸,但也许不是世界末日。一个天真的实现看起来是这样的:
#define EMIT1(c1) __asm _emit c1
#define EMIT2(c1, c2) EMIT1(c1) __asm _emit c2
#define EMIT3(c1, c2, c3) EMIT2(c1, c2) __asm _emit c3
...
#define EMIT63(c1, c2, ..., c63) EMIT62(c1, c2, ..., c62) __asm _emit c63
样品:EMIT7('H','e','l','l','o','!',' ')
。这是朝着正确方向迈出的一步,但并不完全令人信服。首先,您必须根据参数数量选择正确的宏,这很容易出错。让我们试着让编译器为我们选择合适的(基于参数数重载宏):
// get number of arguments with __NARG__
#define __ARG_N(
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10,
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,
_61,_62,_63,N,...) N
#define __RSEQ_N()
63,62,61,60,
59,58,57,56,55,54,53,52,51,50,
49,48,47,46,45,44,43,42,41,40,
39,38,37,36,35,34,33,32,31,30,
29,28,27,26,25,24,23,22,21,20,
19,18,17,16,15,14,13,12,11,10,
9,8,7,6,5,4,3,2,1,0
#define __NARG_I_(...) __ARG_N(__VA_ARGS__)
#define __NARG__(...) __NARG_I_(__VA_ARGS__,__RSEQ_N())
// general definition for any function name
#define _VFUNC_(name, n) name##n
#define _VFUNC(name, n) _VFUNC_(name, n)
#define VFUNC(func, ...) _VFUNC(func, __NARG__(__VA_ARGS__)) (__VA_ARGS__)
// definition for EMIT_STRING
#define EMIT_STRING(...) VFUNC(EMIT, __VA_ARGS__)
由此产生的调用将是EMIT_STRING('H','e','l','l','o','!',' ')
。如果MSC会编译这个。事实证明,情况并非如此。MSC实现__VA_ARGS__
扩展——可以说是正确的——但使用的方式不太有用。幸运的是,"计算机科学中的所有问题都可以通过另一种间接方法来解决",这也不例外(请参阅MSVC没有正确扩展__VA_ARGS__
):
#define EXPAND( x ) x
#define __NARG_I_(...) EXPAND(__ARG_N(__VA_ARGS__))
#define VFUNC(func, ...) EXPAND(_VFUNC(func, __NARG__(__VA_ARGS__)) (__VA_ARGS__))
#define EMIT_STRING(...) VFUNC(EMIT, __VA_ARGS__) __asm _emit ' '
请注意,我将__asm _emit ' '
静默地附加到EMIT_STRING
宏中,这样就不必显式添加NUL终止符。有了它,我们就可以编写EMIT_STRING('H','e','l','l','o','!')
了。
这并不是我上面承诺的那样。如果你想更进一步,你可以使用Charizing Operator(#@)(Microsoft Specific):
#define EMIT1(c1) __asm _emit #@c1
#define EMIT2(c1, c2) EMIT1(c1) __asm _emit #@c2
...
这样做的一个显著限制是,不能再逐字使用,
(逗号)或(空格)字符。必须对它们进行转义,例如使用\ooo转义序列,如
EMIT4
中所示。
完整的参考代码(为简洁起见,省略了
EMIT62
至,
):
#define EMIT1(c1) __asm _emit #@c1
#define EMIT2(c1, c2) EMIT1(c1) __asm _emit #@c2
#define EMIT3(c1, c2, c3) EMIT2(c1, c2) __asm _emit #@c3
...
#define EMIT63(c1, c2, ..., c63) EMIT62(c1, c2, ..., c62) __asm _emit c63
// Workaround for MSC - required since __VA_ARGS__ is interpreted as a single token.
#define EXPAND( x ) x
// get number of arguments with __NARG__
#define __ARG_N(
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10,
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40,
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50,
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60,
_61,_62,_63,N,...) N
#define __RSEQ_N()
63,62,61,60,
59,58,57,56,55,54,53,52,51,50,
49,48,47,46,45,44,43,42,41,40,
39,38,37,36,35,34,33,32,31,30,
29,28,27,26,25,24,23,22,21,20,
19,18,17,16,15,14,13,12,11,10,
9,8,7,6,5,4,3,2,1,0
#define __NARG_I_(...) EXPAND(__ARG_N(__VA_ARGS__))
#define __NARG__(...) __NARG_I_(__VA_ARGS__,__RSEQ_N())
// general definition for any function name
#define _VFUNC_(name, n) name##n
#define _VFUNC(name, n) _VFUNC_(name, n)
#define VFUNC(func, ...) EXPAND(_VFUNC(func, __NARG__(__VA_ARGS__)) (__VA_ARGS__))
// definition for EMIT_STRING
#define EMIT_STRING(...) VFUNC(EMIT, __VA_ARGS__) __asm _emit ' '
限制: