chapter 28 Techniques for Writing C Functions

来源:互联网 发布:公司网络被限制 编辑:程序博客网 时间:2024/05/24 07:13
Both the official API and the auxiliary library provide several mechanisms to
help writing C functions. In this chapter, we cover the mechanisms for array

manipulation, for string manipulation, and for storing Lua values in C.


28.1 Array Manipulation

“Array”, in Lua, is just a name for a table used in a specific way. We can manipulate
arrays using the same functions we use to manipulate tables, namely
lua_settable and lua_gettable. However, the API provides special functions
for array manipulation. One reason for these extra functions is performance:
frequently we have an array-access operation inside the inner loop of an algorithm
(e.g., sorting), so that any performance gain in this operation can have a
big impact on the overall performance of the algorithm. Another reason is convenience:
like string keys, integer keys are common enough to deserve special
treatment.

The API provides two functions for array manipulation:
void lua_rawgeti (lua_State *L, int index, int key);
void lua_rawseti (lua_State *L, int index, int key);


void lua_rawgeti (lua_State *L, int index, int n);

Pushes onto the stack the value t[n],where t is the table at the given index.The access is raw;that is, it does not invoke metamethods.


void lua_rawseti (lua_State *L, int index, int n);

Does the equivalent of t[n] = v,where t is the table at the given indexandv is the value at the top of the stack.

This function pops the value from the stack.The assignment is raw;that is, it does not invoke metamethods.


lua_rawgeti(L,t,key) is equivalent  to the following sequence when t is positive (otherwise, you must compensate
for the new item in the stack):

lua_pushnumber(L, key);
lua_rawget(L, t);


The call lua_rawseti(L,t,key) (again for t positive) is equivalent to this sequence:
lua_pushnumber(L, key);
lua_insert(L, -2); /* put 'key' below previous value */
lua_rawset(L, t);


Note that both functions use raw operations. They are faster and, anyway, tables
used as arrays seldom use metamethods.

我现在说的是writing C funciton, 其实说的是C 里面操作Lua 的数据结构,,,,


As a concrete example of the use of these functions, Listing 28.1 implements
the map function: it applies a given function to all elements of an array, replacing
each element by the result of the call. This example also introduces three
new functions: luaL_checktype, luaL_len, and lua_pcall.


Listing 28.1. The map function in C:

int l_map (lua_State *L) {
    int i, n;
    /* 1st argument must be a table (t) */
    luaL_checktype(L, 1, LUA_TTABLE);
    /* 2nd argument must be a function (f) */
    luaL_checktype(L, 2, LUA_TFUNCTION);
    n = luaL_len(L, 1); /* get size of table */
    for (i = 1; i <= n; i++) {
    lua_pushvalue(L, 2); /* push f */
    lua_rawgeti(L, 1, i); /* push t[i] */
    lua_call(L, 1, 1); /* call f(t[i]) */
    lua_rawseti(L, 1, i); /* t[i] = result */
    }
    return 0; /* no results */
}


The primitive lua_len (not used in the example) is equivalent to the ‘#’
operator. Because of metamethods, this operator may result in any kind of
object, not only numbers; therefore, lua_len returns its result in the stack.
The luaL_len function (the one used in the example, from the auxiliary library)
raises an error if the length is not a number; otherwise, it returns the length as
a C inte
ger.


The lua_call function does an unprotected call. It is similar to lua_pcall,
but it propagates errors, instead of returning an error code. When you are
writing the main code in an application, you should not use lua_call, because
you want to catch any errors. When you are writing functions, however, it is
usually a good idea to use lua_call; if there is an error, just leave it to someone
that cares about it.


--------没看明白这个 map 函数到底怎么个map 法,,,,


28.2 String Manipulation

When a C function receives a string argument from Lua,there are only two rules
that it must observe: not to pop the string from the stack while accessing it and
never to modify the string
.


Things get more demanding when a C function needs to create a string
to return to Lua. Now, it is up to the C code to take care of buffer allocation/
deallocation, buffer overflows, and the like. Nevertheless, the Lua API provides
some functions to help with these tasks.


The standard API provides support for two of the most basic string operations:
substring extraction and string concatenation. To extract a substring, remember
that the basic operation lua_pushlstring gets the string length as an
extra argument. Therefore, if you want to pass to Lua a substring of a string s
ranging from position i to j (inclusive), all you have to do is this:



lua_pushlstring(L, s + i, j - i + 1);



const char *lua_pushlstring (lua_State *L, const char *s, size_t len);

Pushes the string pointed to by s with size lenonto the stack.Lua makes (or reuses) an internal copy of the given string,so the memory ats can be freed or reused immediately afterthe function returns.The string can contain any binary data,including embedded zeros.

Returns a pointer to the internal copy of the string.


As an example, suppose you want a function that splits a string according
to a given separator (a single character) and returns a table with the substrings.
For instance, the call split("hi:ho:there",":") should return the table
{"hi","ho","there"}. Listing 28.2 presents a simple implementation for
this function. It needs no extra buffers and puts no constraints on the size of the
strings it can handle. Lua takes care of all buffer needs.


Listing 28.2. Splitting a string:

static int l_split (lua_State *L) {
    const char *s = luaL_checkstring(L, 1); /* subject */
    const char *sep = luaL_checkstring(L, 2); /* separator */
    const char *e;
    int i = 1;
    lua_newtable(L); /* result table */
    /* repeat for each separator */
    while ((e = strchr(s, *sep)) != NULL) {
    lua_pushlstring(L, s, e-s); /* push substring */
    lua_rawseti(L, -2, i++); /* insert it in table */
    s = e + 1; /* skip separator */
    }
    /* insert last substring */
    lua_pushstring(L, s);
    lua_rawseti(L, -2, i);
    return 1; /* return the table */
}

strchr函数原型:extern char *strchr(const char *s,char c);查找字符串s中首次出现字符c的位置。

char *strchr(const char* _Str,int _Val) -- 单个字符而已
char *strchr(char* _Str,int _Ch)
头文件:#include <string.h>
功能:查找字符串s中首次出现字符c的位置
说明:返回首次出现c的位置的指针,返回的地址是字符串在内存中随机分配的地址再加上你所搜索的字符在字符串位置,如果s中不存在c则返回NULL。
返回值:Returns the address of the first occurrence of the character in the string if successful, or NULL otherwise


can compare with:

strstr(*str1, *str2)实现从字符串str1中查找是否有字符串str2,如果有,从str1中的str2位置起,返回str1中str2起始位置的指针,如果没有,返回null。




To concatenate strings, Lua provides a specific function in its API, called
lua_concat. It is equivalent to the concatenation operator .. in Lua: it converts
numbers to strings and triggers metamethods when necessary. Moreover, it
can concatenate more than two strings at once. The call lua_concat(L,n) will
concatenate (and pop) the n values at the top of the stack, pushing the result on
the top


Another helpful function is lua_pushfstring:
const char *lua_pushfstring (lua_State *L, const char *fmt, ...);

It is somewhat similar to the C function sprintf, in that it creates a string according
to a format string and some extra arguments. Unlike sprintf, however,
you do not need to provide a buffer. Lua dynamically creates the string for you,
as large as it needs to be. The function pushes the resulting string on the stack
and returns a pointer to it. You do not have to worry about buffer overflow
s.


Currently, this function accepts only the following directives:

%s inserts a zero-terminated string
%d inserts an integer
%f inserts a Lua number, that is, a double
%p inserts a pointer
%c inserts an integer as a character
%% inserts the character ‘%’


It accepts no modifiers, such as width or precision.那没有sprintf 强大,,,,

P303





























0 0
原创粉丝点击