栈和寄存器虚拟机比较(以python和lua为例)
指令长度
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为例)的更多相关文章
- Cortex-M3 在C中上报入栈的寄存器和各fault状态寄存器
因为在标准C语音中是不能获取SP指针的.因而,如果想通过C代码来获取入栈的寄存器值,需要配合一小段汇编代码来获取当前的SP值,然后再把这个SP值以参数形式传送给C代码,最后以指针的形式把栈中的各寄存器 ...
- Python、Lua和Ruby之优劣
Python.Lua和Ruby之优劣 Python Python的优点:1.Python比其它语言有更多扩展模块.2.在网上可以找到很多Python教程.不仅如此,还有大量的英文书籍和资料.Pytho ...
- Python、Lua和Ruby——脚本大P.K.
转自Python.Lua和Ruby--脚本大P.K. Python versus Lua Versus Ruby Python.Lua和Ruby--脚本大P.K. Tom Gutschmidt 著 赖 ...
- UltraEdit配置python和lua环境
[语法高亮] 在UltraEdit的wordfile中添加python和lua的语法支持(红色的为python,蓝色的为lua): /L10"Python" Line Commen ...
- Python和Lua的默认作用域以及闭包
默认作用域 前段时间学了下Lua,发现Lua的默认作用域和Python是相反的.Lua定义变量时默认变量的作用域是全局(global,这样说不是很准确,Lua在执行x = 1这样的语句时会从当前环境开 ...
- Python、Lua和Ruby比较——脚本语言大P.K.
译者按:Python.lua和ruby在C/C++是日渐式微的情况下,在java/.net的围歼中努力抗争的三个当红小生.在Tom Gutschmidt的著作<Game Programmng w ...
- Python中的单例设计
01. 单例设计模式 设计模式 设计模式 是 前人工作的总结和提炼,通常,被人们广泛流传的设计模式都是针对 某一特定问题 的成熟的解决方案 使用 设计模式 是为了可重用代码.让代码更容易被他人理解.保 ...
- Cobra —— 可视化Python虚拟机 and 图解python
http://blog.csdn.net/balabalamerobert http://blog.csdn.net/efeics/article/category/1486515 图解python ...
- 用两个栈实现队列(C++ 和 Python 实现)
(说明:本博客中的题目.题目详细说明及参考代码均摘自 “何海涛<剑指Offer:名企面试官精讲典型编程题>2012年”) 题目 用两个栈实现一个队列.队列的声明如下,请实现它的两个函数 a ...
- 【剑指Offer】09. 用两个栈实现队列 解题报告(python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客:http://fuxuemingzhu.cn/ 个人微信公众号:负雪明烛 目录 题目描述 解题方法 一个栈用来保存输入,一个栈用来输出 日 ...
随机推荐
- for循环当中的 var let区别
首先要了解这里代码执行顺序: for循环同步:setTimeout异步: js在执行代码的过程中,碰到同步代码会依次执行,碰到异步代码就会将其放入任务队列中进行等待,当同步代码执行完毕后再开始执行异步 ...
- DevExpress gridControl 字体居住
设置列的标题居中显示: Designer - Views -右侧输入框中输入Appearance-HeaderPanel-TextOptions-设置HAlignment为Center 设置单元格内容 ...
- Python elasticsearch_dsl 报错及解决方法
Exception:maxClauseCount is set to 1024 原因:报错原因是Search限制一个bool查询中最多只能有1024个值或子查询,当超过1024时,会抛出异常. 解决办 ...
- 预处理指令详解(C语言
一.预处理符号 预处理符号是C语言内置的符号,是可以直接使用的. 其中,若遵顼ANSI C,则__STDC__ 为1,否则未定义. 二.#define 1)定义标识符 define可以用来定义标识符, ...
- Python语言课程实验报告 (第三周)
Python语言基础实验(第三周) 一.实验目的和要求 1.了解流程控制语句的结构与类型: 2.学习语句的使用: 3.掌握流程控制语句的实际应用. 二.实验环境 软件版本:Python 3.10 64 ...
- SpringBoot运行就停止
检查下是不是没有引入springboot-starter-web依赖 <dependency> <groupId>org.springframework.boot</gr ...
- vite中使用img标签
<img class="icon-logo" :src="iconsUrl[imgName]" alt="" /> const ...
- JavaSE——构造方法
package com.zhao.test3; public class Student { private String name; private int age; //如果我们自己没有写任何的构 ...
- [746] Interlude Update 3
[746] Interlude Update 3 Client 00 SendProtocolVersion 01 MoveBackwardToLocation 02 Say 03 RequestEn ...
- Delphi模拟win+tab按键效果
//按下左侧win键 keybd_event(VK_LWIN,0,0,0); //按下tab键 keybd_event(VK_TAB,0,0,0); //抬起左侧win键 keybd_event(VK ...