Lua 省略号表达式限制为 248

标签 lua coronasdk ellipsis

我正在为移动应用程序开发的大学类(class)学习 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)

我认为这可能与操作系统相关或与堆栈大小有关,因此我在 Linux 和 Windows 上分别在 32 位和 64 位版本上进行了测试。允许的元素数量保持在 248。这似乎是一个硬编码限制。如果我尝试 > 248 那么我得到的错误是:

main.lua:30 function or expression too complex near <eof>

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

最佳答案

堆栈帧限制

您遇到的限制与允许的最大函数参数数量无关。它大约是 Lua 堆栈帧的最大大小。

以下示例演示了这一点。 Lua 中的局部变量也会占用函数堆栈 frame1 中的槽位,通过声明 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
)

这也是为什么错误信息显示为 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");

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

根据 Roberto Ierusalimschy 的说法,250 这个相对较小的限制是出于性能原因。将堆栈帧大小保持在 256 以下意味着 only 8 bits are needed to store a stack frame offset并且由于每个 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

1:请记住,Lua 脚本的整个主体就像在函数内部一样,因此 Lua 的“顶层”仍然受到那些“堆栈框架”的限制。

关于Lua 省略号表达式限制为 248,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38952744/

相关文章:

lua - 为什么 __add 不起作用?

c++ - 使用 default_converter 和表的 luabind 问题

android - Corona SDK音频在Android上不起作用

error-handling - 第172和218行的Corona SDK错误,没有文件名,只有问号

html - 如何在 html 输入字段中使用文本溢出省略号?

HTML/CSS -- 省略标志左侧的面包屑

css - 在 Angular 5 的三行后显示省略号

c - Lua 5.3-整数-type()-lua_type()

python - 中文字符在lua loadstring中吃掉其他字符

lua - Corona SDK setFillColor 混合颜色时不着色