指令长度

python

python的指令定长,长度为16bit,其中8bit操作码,8bit操作数。

///@file: Python-3.6.0\Include\code.h
typedef uint16_t _Py_CODEUNIT; #ifdef WORDS_BIGENDIAN
# define _Py_OPCODE(word) ((word) >> 8)
# define _Py_OPARG(word) ((word) & 255)
#else
# define _Py_OPCODE(word) ((word) & 255)
# define _Py_OPARG(word) ((word) >> 8)
#endif ///@file: Python-3.6.0\Python\ceval.c
PyObject *
_PyEval_EvalFrameDefault(PyFrameObject *f, int throwflag)
{
///...
#define NEXTOPARG() do { \
_Py_CODEUNIT word = *next_instr; \
opcode = _Py_OPCODE(word); \
oparg = _Py_OPARG(word); \
next_instr++; \
} while (0)
}

lua

lua一条指令的长度为一个int,也就是32bit,其中操作码为6bit,剩余的操作数有26bit。由于操作数中有一些用来编码寄存器的编号,所以单条指令比python的指令要长(32bit vs 16 bits)。

///@file: lua-5.3.4\src\lopcodes.h
/*===========================================================================
We assume that instructions are unsigned numbers.
All instructions have an opcode in the first 6 bits.
Instructions can have the following fields:
'A' : 8 bits
'B' : 9 bits
'C' : 9 bits
'Ax' : 26 bits ('A', 'B', and 'C' together)
'Bx' : 18 bits ('B' and 'C' together)
'sBx' : signed Bx A signed argument is represented in excess K; that is, the number
value is the unsigned value minus K. K is exactly the maximum value
for that argument (so that -max is represented by 0, and +max is
represented by 2*max), which is half the maximum for the corresponding
unsigned argument.
===========================================================================*/ enum OpMode {iABC, iABx, iAsBx, iAx}; /* basic instruction format */

add为例

add是我们最为熟悉的基础操作,可能大家上学最开始学习的就是加法,设置不需要上学大家都需要使用加法。

python

python的加法默认就是取栈顶最顶端的两个元素,求和之后再次压入堆栈顶端。

        TARGET(BINARY_AND) {
PyObject *right = POP();
PyObject *left = TOP();
PyObject *res = PyNumber_And(left, right);
Py_DECREF(left);
Py_DECREF(right);
SET_TOP(res);
if (res == NULL)
goto error;
DISPATCH();
}

lua

在lua的操作中,加法的a = b + c,三个操作数都是由指令中的寄存器指定,而不是跟栈顶位置强绑定。

      vmcase(OP_ADD) {
TValue *rb = RKB(i);
TValue *rc = RKC(i);
lua_Number nb; lua_Number nc;
if (ttisinteger(rb) && ttisinteger(rc)) {
lua_Integer ib = ivalue(rb); lua_Integer ic = ivalue(rc);
setivalue(ra, intop(+, ib, ic));
}
else if (tonumber(rb, &nb) && tonumber(rc, &nc)) {
setfltvalue(ra, luai_numadd(L, nb, nc));
}
else { Protect(luaT_trybinTM(L, rb, rc, ra, TM_ADD)); }
vmbreak;
}

指令生成

在lua的指令生成中,对于a = b * c + d * e的解析时,在第一个表达式b * c 完成之后,解析 d * e之前,已经为b * c的结果分配了寄存器。这也是lua的一个重要特点:它并没有语法树,虚拟机指令是在语法解析的同时实时生成的。作为对比,如果要使用基于堆栈的虚拟机,那么在对a计算加法的时候,必须要先完成bc和de两个子表达式的计算只有才能生成两个子表达式的加法。

/*
** Process 1st operand 'v' of binary operation 'op' before reading
** 2nd operand.
*/
void luaK_infix (FuncState *fs, BinOpr op, expdesc *v) {
switch (op) {
case OPR_AND: {
luaK_goiftrue(fs, v); /* go ahead only if 'v' is true */
break;
}
case OPR_OR: {
luaK_goiffalse(fs, v); /* go ahead only if 'v' is false */
break;
}
case OPR_CONCAT: {
luaK_exp2nextreg(fs, v); /* operand must be on the 'stack' */
break;
}
case OPR_ADD: case OPR_SUB:
case OPR_MUL: case OPR_DIV: case OPR_IDIV:
case OPR_MOD: case OPR_POW:
case OPR_BAND: case OPR_BOR: case OPR_BXOR:
case OPR_SHL: case OPR_SHR: {
if (!tonumeral(v, NULL))
luaK_exp2RK(fs, v);
/* else keep numeral, which may be folded with 2nd operand */
break;
}
default: {
luaK_exp2RK(fs, v);
break;
}
}
}

lua寄存器编号溢出

寄存器编号最短是8bits,这8bits可表示的正整数最大值是256,如果表达式太复杂,是不是会造成寄存器编号无法编码到指令中呢?

生成测试代码

tsecer@harry: cat genloop.py
import sys
sys.setrecursionlimit(1500) def pexp(level):
if level > 0:
print('( a + ', end='')
pexp(level - 1)
print(')', end='')
print('a = 1')
pexp(1000)
tsecer@harry: python3 genloop.py > reg.overflow.lua

生成的lua代码大致这样

a = 1
( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ( a + ))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))))

嵌套层数先溢出

执行之后发现还没有到寄存器分配就已经报错,而此时freereg只用到了99个。

tsecer@harry: src/luac -l reg.overflow.lua
src/luac: reg.overflow.lua:2: too many C levels (limit is 200) in main function near 'a'
tsecer@harry:
(gdb) bt
#0 errorlimit (fs=0x7fffffffbab0, limit=200, what=0x4268ae "C levels") at lparser.c:80
#1 0x00000000004101c5 in checklimit (fs=0x7fffffffbab0, v=201, l=200, what=0x4268ae "C levels") at lparser.c:93
#2 0x0000000000410cff in enterlevel (ls=0x7fffffffbaf0) at lparser.c:334
#3 0x0000000000412ab1 in subexpr (ls=0x7fffffffbaf0, v=0x7fffffff1320, limit=0) at lparser.c:1051
#4 0x0000000000412c15 in expr (ls=0x7fffffffbaf0, v=0x7fffffff1320) at lparser.c:1079
#5 0x00000000004124ac in primaryexp (ls=0x7fffffffbaf0, v=0x7fffffff1320) at lparser.c:877
#6 0x0000000000412541 in suffixedexp (ls=0x7fffffffbaf0, v=0x7fffffff1320) at lparser.c:898
#7 0x0000000000412871 in simpleexp (ls=0x7fffffffbaf0, v=0x7fffffff1320) at lparser.c:978
#8 0x0000000000412b25 in subexpr (ls=0x7fffffffbaf0, v=0x7fffffff1320, limit=10) at lparser.c:1059
#9 0x0000000000412b88 in subexpr (ls=0x7fffffffbaf0, v=0x7fffffff14d0, limit=0) at lparser.c:1069
(gdb) p fs->freereg
$6 = 99 'c'
(gdb)

对应的代码

static BinOpr subexpr (LexState *ls, expdesc *v, int limit) {
BinOpr op;
UnOpr uop;
enterlevel(ls);
///...
} static void enterlevel (LexState *ls) {
lua_State *L = ls->L;
++L->nCcalls;
checklimit(ls->fs, L->nCcalls, LUAI_MAXCCALLS, "C levels");
} /*
** maximum depth for nested C calls and syntactical nested non-terminals
** in a program. (Value must fit in an unsigned short int.)
*/
#if !defined(LUAI_MAXCCALLS)
#define LUAI_MAXCCALLS 200
#endif

修改LUAI_MAXCCALLS宏

如果把LUAI_MAXCCALLS这个值修改的足够大呢,例如1024?可以看到,lua依然有运行时检测会提前结束(而不是生成错误的字节码):

/* Maximum number of registers in a Lua function (must fit in 8 bits) */
#define MAXREGS 255
/*
** Check register-stack level, keeping track of its maximum size
** in field 'maxstacksize'
*/
void luaK_checkstack (FuncState *fs, int n) {
int newstack = fs->freereg + n;
if (newstack > fs->f->maxstacksize) {
if (newstack >= MAXREGS)
luaX_syntaxerror(fs->ls,
"function or expression needs too many registers");
fs->f->maxstacksize = cast_byte(newstack);
}
}

通过gdb看调用链入下图所示

Breakpoint 2, luaK_checkstack (fs=0x7fffffffbab0, n=1) at lcode.c:365
365 luaX_syntaxerror(fs->ls,
(gdb) p fs->freereg
$2 = 254 '\376'
(gdb) bt
#0 luaK_checkstack (fs=0x7fffffffbab0, n=1) at lcode.c:365
#1 0x0000000000420e55 in luaK_reserveregs (fs=0x7fffffffbab0, n=1) at lcode.c:376
#2 0x0000000000421a4f in luaK_exp2nextreg (fs=0x7fffffffbab0, e=0x7ffffffe0d90) at lcode.c:706
#3 0x0000000000421b08 in luaK_exp2anyreg (fs=0x7fffffffbab0, e=0x7ffffffe0d90) at lcode.c:725
#4 0x0000000000421cb2 in luaK_exp2RK (fs=0x7fffffffbab0, e=0x7ffffffe0d90) at lcode.c:775
#5 0x0000000000422800 in luaK_infix (fs=0x7fffffffbab0, op=OPR_ADD, v=0x7ffffffe0d90) at lcode.c:1106
#6 0x0000000000412bb9 in subexpr (ls=0x7fffffffbaf0, v=0x7ffffffe0d90, limit=0) at lparser.c:1067
#7 0x0000000000412c67 in expr (ls=0x7fffffffbaf0, v=0x7ffffffe0d90) at lparser.c:1079
#8 0x00000000004124fc in primaryexp (ls=0x7fffffffbaf0, v=0x7ffffffe0d90) at lparser.c:877
#9 0x0000000000412591 in suffixedexp (ls=0x7fffffffbaf0, v=0x7ffffffe0d90) at lparser.c:898
#10 0x00000000004128c3 in simpleexp (ls=0x7fffffffbaf0, v=0x7ffffffe0d90) at lparser.c:978
#11 0x0000000000412b77 in subexpr (ls=0x7fffffffbaf0, v=0x7ffffffe0d90, limit=10) at lparser.c:1059
#12 0x0000000000412bda in subexpr (ls=0x7fffffffbaf0, v=0x7ffffffe0f40, limit=0) at lparser.c:1069

作者的说明

在lua作者的说明文档中,有大量的篇幅(第7部分"The Virtual Machine")说明了lua在实现时在基于stack和register之间的考虑。在5.0之前,lua一直使用的是基于堆栈的虚拟机,在2003年发布的5.0版本之后,lua开始使用基于寄存器的虚拟机。

作者提到两个优点:

  • 避免push/pop操作

    使用寄存器避免了代价很高的push/pop操作,因为操作数必须在栈顶,所以在执行动作之前必须要先push到堆栈上,反之在动作完成之后从堆栈上pop掉。考虑到这些push和pop可能会涉及到数值拷贝,或者操作数引用计数的增加,这个代价比较高。
  • 实时生成代码

    Some authors also defend registerbased virtual machines based on their suitability for on-the-fly compilation。

指令指针(pc)递增的时机

在lua和python中都有一个有意思的现象,就是先取出指令内容,然后递增pc指针,然后再解码并执行指令(注意:不是在指令解码并执行之后才递增pc)。这样的好处个人理解是对于call这种指令,在解码执行前就递增的话,当执行call的时候,自动保存的返回地址就是下一条指令,这样实现call指令更简单一些。

这一点应该和硬件CPU的处理方法相同,这也意味着,当在gdb中设置数据断点时,命中之后pc指针指向的是触发该断点指令的下一条指令。

lua

lua的解码执行

/* fetch an instruction and prepare its execution */
#define vmfetch() { \
i = *(ci->u.l.savedpc++); /* main loop of interpreter */
for (;;) {
Instruction i;
StkId ra;
vmfetch();

python

lua的解码执行

#define NEXTOPARG()  do { \
_Py_CODEUNIT word = *next_instr; \
opcode = _Py_OPCODE(word); \
oparg = _Py_OPARG(word); \
next_instr++; \
} while (0) for (;;) {
NEXTOPARG();
dispatch_opcode:
#ifdef DYNAMIC_EXECUTION_PROFILE
#ifdef DXPAIRS
dxpairs[lastopcode][opcode]++;
lastopcode = opcode;
#endif
dxp[opcode]++;
#endif #ifdef LLTRACE
/* Instruction tracing */ if (lltrace) {
if (HAS_ARG(opcode)) {
printf("%d: %d, %d\n",
f->f_lasti, opcode, oparg);
}
else {
printf("%d: %d\n",
f->f_lasti, opcode);
}
}
#endif switch (opcode) { /* BEWARE!
It is essential that any operation that fails sets either
x to NULL, err to nonzero, or why to anything but WHY_NOT,
and that no operation that succeeds does this! */ TARGET(NOP)
FAST_DISPATCH();

文档资料

指令周期这个文档还可以看到提前递增pc的重要原因:现在的cpu都是流水线的,在取指令之后递增pc,这样在指令解码执行的时候,取地址的逻辑单元就可以继续取指令,从而形成流水线。

In simpler CPUs, the instruction cycle is executed sequentially, each instruction being processed before the next one is started. In most modern CPUs, the instruction cycles are instead executed concurrently, and often in parallel, through an instruction pipeline: the next instruction starts being processed before the previous instruction has finished, which is possible because the cycle is broken up into separate steps.[1]

栈和寄存器虚拟机比较(以python和lua为例)的更多相关文章

  1. Cortex-M3 在C中上报入栈的寄存器和各fault状态寄存器

    因为在标准C语音中是不能获取SP指针的.因而,如果想通过C代码来获取入栈的寄存器值,需要配合一小段汇编代码来获取当前的SP值,然后再把这个SP值以参数形式传送给C代码,最后以指针的形式把栈中的各寄存器 ...

  2. Python、Lua和Ruby之优劣

    Python.Lua和Ruby之优劣 Python Python的优点:1.Python比其它语言有更多扩展模块.2.在网上可以找到很多Python教程.不仅如此,还有大量的英文书籍和资料.Pytho ...

  3. Python、Lua和Ruby——脚本大P.K.

    转自Python.Lua和Ruby--脚本大P.K. Python versus Lua Versus Ruby Python.Lua和Ruby--脚本大P.K. Tom Gutschmidt 著 赖 ...

  4. UltraEdit配置python和lua环境

    [语法高亮] 在UltraEdit的wordfile中添加python和lua的语法支持(红色的为python,蓝色的为lua): /L10"Python" Line Commen ...

  5. Python和Lua的默认作用域以及闭包

    默认作用域 前段时间学了下Lua,发现Lua的默认作用域和Python是相反的.Lua定义变量时默认变量的作用域是全局(global,这样说不是很准确,Lua在执行x = 1这样的语句时会从当前环境开 ...

  6. Python、Lua和Ruby比较——脚本语言大P.K.

    译者按:Python.lua和ruby在C/C++是日渐式微的情况下,在java/.net的围歼中努力抗争的三个当红小生.在Tom Gutschmidt的著作<Game Programmng w ...

  7. Python中的单例设计

    01. 单例设计模式 设计模式 设计模式 是 前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对 某一特定问题 的成熟的解决方案 使用 设计模式 是为了可重用代码.让代码更容易被他人理解.保 ...

  8. Cobra —— 可视化Python虚拟机 and 图解python

    http://blog.csdn.net/balabalamerobert http://blog.csdn.net/efeics/article/category/1486515  图解python ...

  9. 用两个栈实现队列(C++ 和 Python 实现)

    (说明:本博客中的题目.题目详细说明及参考代码均摘自 “何海涛<剑指Offer:名企面试官精讲典型编程题>2012年”) 题目 用两个栈实现一个队列.队列的声明如下,请实现它的两个函数 a ...

  10. 【剑指Offer】09. 用两个栈实现队列 解题报告(python & C++)

    作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人微信公众号:负雪明烛 目录 题目描述 解题方法 一个栈用来保存输入,一个栈用来输出 日 ...

随机推荐

  1. 微信小程序扫码

    前言:微信小程序-->调用摄像头,扫描二维码/条形码,并获取信息,一连串操作,只需要调用微信小程序提供的 wx.scanCode API. 一.生成测试二维码 随便网上找个二维码生成器. 二.实 ...

  2. uniapp 提示 打包时未添加 push模块

    最近打包上架的  ios项目  启动项目提示打包时未添加  push模块 在uniapp  manifest中可以配置消息推送,可以我们项目没有用到这个功能,真是日狗了,排除半天仔细检查了使用Push ...

  3. 洛谷P2205 [USACO13JAN]Painting the Fence S

    题目 https://www.luogu.com.cn/problem/P2205 思路 刷水题真解压 差分就完事了 值得注意的一些东西:像这种和数轴或者坐标相关的题,还有扫描线题,一定要注意区间的开 ...

  4. UVM——通过一个简单的testbench来了解UVM组件的phase执行顺序

    先写好一个top.sv 查看代码 // 导入VCS或者Modelsim自带的UVM库和宏 `include "uvm_macros.svh" import uvm_pkg::*; ...

  5. vue真实项目结构

    我明白你的需求.如果你想看一个真实企业项目使用的复杂目录结构,你可以参考以下几个例子: 根据1的介绍,一个vue项目的目录结构可以细分为以下几个部分: |- src | |- api 存放所有请求接口 ...

  6. 论文阅读: CCF A 2022 MVD: 基于流敏感图神经网络的内存相关漏洞检测 (ICSE)

    Motivation: 内存相关漏洞会导致性能下降和程序崩溃,严重威胁到现代软件的安全性. 静态分析方法使用一些预定义的漏洞规则或模式来搜索不正确的内存操作,然而,定义良好的漏洞规则或模式高度依赖于专 ...

  7. Linux系统开机自启动jar包程序

    一.编写jenkins开机自启动脚本 vim /etc/rc.d/init.d/jenkins.sh #!/bin/bash export JAVA_HOME=/usr/lib/jvm/java ex ...

  8. 【QT】打包QT程序

    发布QT程序时需要把依赖的库拷贝到程序所在文件夹下,可以使用如下方式: 命令行输入cmd,cd 到程序所在文件夹,输入windeployqt xx.exe --release 注xx.exe是程序的名 ...

  9. Mysql之迂回连接术

    转载请注明来源:https://www.cnblogs.com/Sherlock-L/p/14932870.html 关键词:OmniDB.Mysql Router 背景:项目的测试数据库放在了生产机 ...

  10. 利用shell脚本来监控linux系统的负载与CPU占用情况

    一.安装linux下面的一个邮件客户端msmtp软件(类似于一个foxmail的工具) 1.下载安装: http://downloads.sourceforge.net/msmtp/msmtp-1.4 ...