User-Defined Types in C

User-Defined Types in C作为《Programming in Lua third edition》的第29章,引入了一个新的数据类型userdata,并向我们介绍如何在Lua中实现C语言的数组。除此之外,其余的内容都在总结过往的章节,比如:原表(metatable)、原函数的使用。同样,首先给出文章的结果:

array = require("array") --[[连接一个自己封装的动态库array.dll]]

a = array.new(1000)      --[[开辟1000 bits大小的空间]]
a[5] = true              --[[第5/3/20bit的位置赋值为true]]
a[3] = true;
a[20] =true;
print(a)                 --[[输出这个数组对象:array(1000):  range[0 - 20] = 00101000000000000001]]

下面介绍array.dll的代码,没有什么特殊之处,对着书本一个个字符的敲。源码下载

#include <Windows.h>

extern "C"{
#include <lua.h>
#include <lauxlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <lualib.h>
#include <math.h>
#include <limits.h>
}
#define BITS_PER_WORD (CHAR_BIT*sizeof(unsigned int))
#define I_WORD(i)   ((unsigned int)(i)/BITS_PER_WORD)
#define I_BIT(i)    (1 << ((unsigned int)(i) % BITS_PER_WORD))

#define checkarray(L) (NumArray *)luaL_checkudata(L, 1, "LuaBook.array")

int maxIndex = 0;
int tempMaxIndex = -1;
typedef struct NumArray
{
    int size;
    unsigned int values[1];
}NumArray;

--[[error函数:输出错误信息并退出程序]]
void error(lua_State *L, const char *fmt, ...)
{
    va_list argp;
    va_start(argp, fmt);
    vfprintf(stderr, fmt, argp);
    va_end(argp);
    lua_close(L);
    exit(EXIT_FAILURE);
}

static int newarray(lua_State *L)
{
    int i, n;
    size_t nbytes;
    NumArray *a;
    n = luaL_checkint(L, 1);--[[在lua中调用C函数的时候,第一个参数的位置总是1,因为此时每个函数都有一个局部的栈。但是如果在其他C函数中调用此函数,就不成立了。]]
    luaL_argcheck(L, n >= 1, 1, "invalid size");
    nbytes = sizeof(NumArray) + I_WORD(n - 1) * sizeof(unsigned int);
    a = (NumArray *)lua_newuserdata(L, nbytes);
    a->size = n;
    for (i = 0; i <= I_WORD(n-1); i ++)
        a->values[i] = 0;

    luaL_getmetatable(L, "LuaBook.array");
    lua_setmetatable(L, -2);

    return 1;
}

static unsigned int * getindex(lua_State *L, unsigned int *mask)
{
    NumArray *a = checkarray(L);
    int index = luaL_checkint(L, 2) - 1;
    tempMaxIndex = index+1;
    luaL_argcheck(L, 0 <= index && index < a->size, 2, "index out of range");
    /*return element address */
    *mask = I_BIT(index);
    return &a->values[I_WORD(index)];
}

static int setarray(lua_State *L)
{
    unsigned int mask;
    unsigned int *entry = getindex(L, &mask);

    luaL_checkany(L, 3); --[[必须要有第三个参数,否则error]]
    if(!lua_isboolean(L, 3)) --[[课后习题要求检查是否为boolean类型,如果不是就结束程序。]]
        error(L, "A boolean number is required!\n");

    if (lua_toboolean(L, 3))
    {
        *entry |= mask;
        if (tempMaxIndex != -1 && tempMaxIndex > maxIndex)
        {
            maxIndex = tempMaxIndex;
            tempMaxIndex = -1;
        }
    }
    else
        *entry &= ~mask;
    return 0;
}

static int getarray(lua_State *L)
{
    unsigned int mask;
    unsigned int *entry = getindex(L, &mask);
    tempMaxIndex = -1;
    lua_pushboolean(L, *entry & mask);
    return 1;
}

static int getsize (lua_State *L)
{
    NumArray * a = checkarray(L);
    luaL_argcheck(L, a != NULL, 1, "'array' expected");
    lua_pushinteger(L, a->size);
    return 1;
}

int array2string(lua_State *L)
{
    NumArray *a = checkarray(L);

    char *str = (char *)malloc(maxIndex+1);
    for (int i = 0; i < maxIndex; i ++)
    {
        bool k = (a->values[I_WORD(i)] & I_BIT(i))? 1:0;
        str[i] = k + 48;
    }
    str[maxIndex] = 0;
    lua_pushfstring(L, "array(%d):  range[0 - %d] = %s", a->size, maxIndex, str);

    free(str);
    return 1;
}

static const struct luaL_Reg arraylib_f[] =
{
    {"new", newarray},
    {NULL, NULL}
};

static const struct luaL_Reg arraylib_m[] = 
{
    {"__tostring", array2string},
    {"__newindex", setarray},
    {"__index", getarray},
    {"__len", getsize},
    {NULL, NULL}
};

extern "C" int __declspec(dllexport) luaopen_array(lua_State *L)
{
    luaL_newmetatable(L, "LuaBook.array");
    luaL_setfuncs(L, arraylib_m, 0);
    luaL_newlib(L, arraylib_f);
    return 1;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值