Lua Ellipsis表达限于248

Rhe*_*xis 4 lua ellipsis coronasdk

我正在学习Lua在移动应用程序开发中的大学课程,最近我们讨论了省略号运算符(...),允许动态数量的参数.出于好奇,我决定尝试找出它能够处理多少个参数的限制,因为事实证明它是248.

例如:

function pr(...)
    print(...)
end

pr(1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1, 1, 1, 1, 1, 1, 1, 1)
Run Code Online (Sandbox Code Playgroud)

我想也许它取决于操作系统或与堆栈大小有关,所以我在Linux和Windows上测试了这个,每个都是32位和64位版本.允许的元素数量保持在248.这似乎是一个硬编码限制.如果我尝试> 248然后我得到的错误是:

main.lua:30 function or expression too complex near <eof>
Run Code Online (Sandbox Code Playgroud)

在大多数情况下,我无法想象任何人需要超过248个表达式,但对于那些情况,有没有办法绕过这个?另外,为什么它是248?这个数字似乎并不特别.

hug*_*omg 6

堆栈帧限制

您遇到的限制并不直接与允许的最大功能参数数有关.它关于Lua堆栈帧的最大大小.

以下示例演示了这一点.Lua中的局部变量也使用了函数堆栈帧1中的槽,并且通过声明200个局部变量,我们现在只需要打印函数中的48个参数即可达到限制:

local x001,x002,x003,x004,x005,x006,x007,x008,x009,x010
local x011,x012,x013,x014,x015,x016,x017,x018,x019,x020
local x021,x022,x023,x024,x025,x026,x027,x028,x029,x030
local x031,x032,x033,x034,x035,x036,x037,x038,x039,x040
local x041,x042,x043,x044,x045,x046,x047,x048,x049,x050
local x051,x052,x053,x054,x055,x056,x057,x058,x059,x060
local x061,x062,x063,x064,x065,x066,x067,x068,x069,x070
local x071,x072,x073,x074,x075,x076,x077,x078,x079,x080
local x081,x082,x083,x084,x085,x086,x087,x088,x089,x090
local x091,x092,x093,x094,x095,x096,x097,x098,x099,x100
local x101,x102,x103,x104,x105,x106,x107,x108,x109,x110
local x111,x112,x113,x114,x115,x116,x117,x118,x119,x120
local x121,x122,x123,x124,x125,x126,x127,x128,x129,x130
local x131,x132,x133,x134,x135,x136,x137,x138,x139,x140
local x141,x142,x143,x144,x145,x146,x147,x148,x149,x150
local x151,x152,x153,x154,x155,x156,x157,x158,x159,x160
local x161,x162,x163,x164,x165,x166,x167,x168,x169,x170
local x171,x172,x173,x174,x175,x176,x177,x178,x179,x180
local x181,x182,x183,x184,x185,x186,x187,x188,x189,x190
local x191,x192,x193,x194,x195,x196,x197,x198,x199,x200
print(
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1,1,1,
1,1,1,1,1,1,1,1
)
Run Code Online (Sandbox Code Playgroud)

这也是错误消息读取function or expression too complex而不是too many arguments passed to function沿着这些行读取的原因.

为什么248?

堆栈帧的最大大小实际为249.在llimits.h中,Lua将MAXSTACK定义为250,而在lcode.c中,checkstack函数仅允许于此的堆栈帧.

 if (newstack >= MAXSTACK)
      luaX_syntaxerror(fs->ls, "function or expression too complex");
Run Code Online (Sandbox Code Playgroud)

这与我们在实验中得到的结果相符.函数调用的字节码f(a1,a2,...,an)将需要N+1堆栈上的寄存器:一个指向我们正在调用的函数,一个指向函数的参数,248 + 1 = 249 <= 250.(我们还需要额外的寄存器如果使用函数的返回值)

根据Roberto Ierusalimschy的说法,这个相对较小的限制为250的原因是出于性能原因.将堆栈帧大小保持在256以下意味着只需要8位来存储堆栈帧偏移,并且由于每个Lua字节码包含2或3个这些堆栈偏移作为参数,因此使用较少的字节来存储偏移非常重要.

如何将超过250个参数传递给函数

回到原始问题,实际上可以将超过256个参数传递给可变参数函数.如果不使用大量以逗号分隔的参数,而是解包表或使用其他返回多个结果的函数,那么我们必须面对的限制是整个Lua堆栈的大小而不是单个堆栈帧的大小.此限制(LUA_MAXSTACK)是用户可配置的luaconf.h,默认情况下为1000000.

function rep(n)
  local t = {}
  for i = 1, n do
    t[i] = i
  end
  return t
end

function foo(...)
end

foo(table.unpack(rep(999986))) -- Pretty close to 1000000
Run Code Online (Sandbox Code Playgroud)

1:请记住,Lua脚本的整个主体的行为就像它在函数内部一样,因此Lua"toplevel"仍然受制于那些"堆栈框架"限制.