This first edition was written for Lua 5.0. While still largely relevant for later versions, there are some differences.
The fourth edition targets Lua 5.3 and is available at Amazon and other bookstores.
By buying the book, you also help to support the Lua project.

24.2 – The Stack

We face two problems when trying to exchange values between Lua and C: the mismatch between a dynamic and a static type system and the mismatch between automatic and manual memory management.

In Lua, when we write a[k] = v, both k and v can have several different types (even a may have different types, due to metatables). If we want to offer this operation in C, however, any settable function must have a fixed type. We would need dozens of different functions for this single operation (one function for each combination of types for the three arguments).

We could solve this problem by declaring some kind of union type in C, let us call it lua_Value, that could represent all Lua values. Then, we could declare settable as

    void lua_settable (lua_Value a, lua_Value k, lua_Value v);
This solution has two drawbacks. First, it can be difficult to map such a complex type to other languages; Lua has been designed to interface easily not only with C/C++, but also with Java, Fortran, and the like. Second, Lua does garbage collection: If we keep a Lua value in a C variable, the Lua engine has no way to know about this use; it may (wrongly) assume that this value is garbage and collect it.

Therefore, the Lua API does not define anything like a lua_Value type. Instead, it uses an abstract stack to exchange values between Lua and C. Each slot in this stack can hold any Lua value. Whenever you want to ask for a value from Lua (such as the value of a global variable), you call Lua, which pushes the required value on the stack. Whenever you want to pass a value to Lua, you first push the value on the stack, and then you call Lua (which will pop the value). We still need a different function to push each C type on the stack and a different function to get each value from the stack, but we avoid the combinatorial explosion. Moreover, because this stack is managed by Lua, the garbage collector knows which values C is using.

Nearly all functions in the API use the stack. As we saw in our first example, luaL_loadbuffer leaves its result on the stack (either the compiled chunk or an error message); lua_pcall gets the function to be called from the stack and leaves any occasional error message there.

Lua manipulates this stack in a strict LIFO discipline (Last In, First Out; that is, always through the top). When you call Lua, it only changes the top part of the stack. Your C code has more freedom; specifically, it can inspect any element inside the stack and even insert and delete elements in any arbitrary position.