Monthly Archives: September 2014

What I am thinking when I am writing C and Java

It is really different feelings. When I am writing the C code it forces me to must think about data structure at first time. But when I write C++/Java I always think about abstraction and behavior (methods) as starting point.

Once upon a time and even today I like C++/Java thinking style very much and abstract class and behavior and make general OOP design.

But as time go when I deal with some really complicated problems I am aware of like a lot of expert said data structure is much more important than abstraction, behavior or algorithm. Especially recently I am reading source code of Lua and Redis I am so surprised these C code is amazing. And also I put myself to think if I am author how I can start and implement them as C++/Java programmer. A lot of abstraction and a lot of methods fill in my minds immediately I am almost lost and I can’t find a easy starting point although there are so much methodologies about OOD. Maybe I can write pretty much code at abstract level such as VirtureMachine interface including compile and execute abstract methods but I know it’s nothing. I will take a lot of time to think about non-meaningful code, I am escaping from the most difficult part, like this.

As another simple example with pretty much circumstances we hope a method execution running with a specific context or container. When I use C++/Java it is pretty obviously that I provide a Context interface and inject to domain object and at this time I haven’t known anything about Context details and I just put everything, in general a lot of geXXX() methods other service methods which I need get from Context. Everything is good.

But when I suppose I am a C programmer it seems becoming different. I have to think about its internal implementation and carefully design structure and a series methods on it and also these methods sequence dependency such as init method must be called before other methods. At this time possibly you will said structure is just like a class only containing data you can do same thing with OO language but it is different as OOD it is abnormal that a class not containing methods. And OOD always firstly emphasize behavior’s importance.

But with a lot of circumstance data structure is much more important than behavior and abstraction. It is so directly to focus the core problems and avoid bad taste of over-design and it seems impossible that C program has over-design problem, and it decide how you start any other things.   Around data structure to design system is always a tradition of unix/linux C programmers.  It is not easy to master and I think that’s why OOD is so popular you are always able to start writing something even you are not clear how to implement it.

A good C programmer either can not start programming at all without data structure or resolve problem smoothly and almost perfectly around the several  data structure.

As a Java programmer it take so many times to design abstraction and carefully use all kinds of design patterns to generate tons of code but the problem is still there. Refactoring and redesign almost distribute the whole development life cycle.

Lua 源代码学习 – (1)

像一切的C程序一样,Lua解释器的main函数入口定义在Lua.c文件里,

int main (int argc, char **argv) {
  int status, result;
  lua_State *L = luaL_newstate();  /* create state */
  if (L == NULL) {
    l_message(argv[0], "cannot create state: not enough memory");
    return EXIT_FAILURE;
  }
  /* call 'pmain' in protected mode */
  lua_pushcfunction(L, &pmain);
  lua_pushinteger(L, argc);  /* 1st argument */
  lua_pushlightuserdata(L, argv); /* 2nd argument */
  status = lua_pcall(L, 2, 1, 0);
  result = lua_toboolean(L, -1);  /* get result */
  finalreport(L, status);
  lua_close(L);
  return (result && status == LUA_OK) ? EXIT_SUCCESS : EXIT_FAILURE;
}

虽然我抑制不住地想讲lua_State这个核心的数据结构,但是还是决定放在后面虚拟机的部分讲。让我们先有个直观的概念,当你在shell敲下lua的时候发生了什么。

这段启动代码有趣的地方在于main函数马上把控制权交给了pmain函数,虽然你可以很容易找到pmain的定义就在同一个文件里,但是Lua调用它的方式相当不直接,先push各种参数进lua_State,然后调用lua_pcall,这种调用方式就是注释里所说的protected mode。参数push的顺序只要pmain函数自己能够理解就好,但是第一个一定要是要调用的函数指针。lua_pcall只是lua_pcallk函数的一个宏定义,lua_pcallk定义在Lapi.c里,如果你想用lua_pcallk让lua虚拟机调用你的C函数,首先函数一定要具有int (*)(lua_State *L)的签名,然后可以仿照这里调用pmain的方法去调用。

下面我们看看真正的lua_pcallk做了什么事情,

LUA_API int lua_pcallk (lua_State *L, int nargs, int nresults, int errfunc,
                        int ctx, lua_CFunction k) {
  struct CallS c;
  ...
  ...
  c.func = L->top - (nargs+1);  /* function to be called */
  if (k == NULL || L->nny > 0) {  /* no continuation or no yieldable? */
    c.nresults = nresults;  /* do a 'conventional' protected call */
    status = luaD_pcall(L, f_call, &c, savestack(L, c.func), func);
  }
  else {  /* prepare continuation (call is already protected by 'resume') */
    ...
    ...
  }
  adjustresults(L, nresults);
  lua_unlock(L);
  return status;
}

我们先看主要的几点,
1. 声明了一个struct CallS c,并且把我们调用之前push进state的pmain函数指针设置进去c.func = L->top – (nargs+1),看看这个表达式,这就是刚开始强调的要把函数指针第一个push进state的原因。
2. 调用luaD_pcall(L, f_call, &c, savestack(L, c.func), func),这个时候pmain还是没有被真正的调用到,这个函数里是要调用f_call函数,如果你要在你的代码里直接使用luaD_pcall函数的话,第二个参数一定得具有void (*)(lua_State *L, void *ud)的签名。
3. 我们接着往下继续看,luaD_pcall里也不会直接调用f_call(L,c),它又包装了一层去调用luaD_rawrunprotected(L, f_call, c)。
4. 在luaD_rawrunprotected里,终于调用到了f_call(L,c),等等pmain在哪里呢?让我们检查f_call的定义,

static void f_call (lua_State *L, void *ud) {
  struct CallS *c = cast(struct CallS *, ud);
  luaD_call(L, c->func, c->nresults, 0);
}

上帝啊,luaD_call又是怎么回事,不过这次至少我们把pmain的值(c->func)传给它了,要是它不用,我们干吗传给它,相信直觉,胜利就在眼前了,

void luaD_call (lua_State *L, StkId func, int nResults, int allowyield) {
  ...
  ...
  if (!luaD_precall(L, func, nResults))  /* is a Lua function? */
    luaV_execute(L);  /* call it */
  if (!allowyield) L->nny--;
  L->nCcalls--;
}

崩溃,胖子,你说的胜利呢?好吧,答案在luaD_precall(L, func, nResults)

int luaD_precall (lua_State *L, StkId func, int nresults) {
  lua_CFunction f;
  ...
  ...
  ...
     Cfunc:
      ...
      ...
      n = (*f)(L);  /* do the actual call */
      lua_lock(L);
      ...
      ...
}

泪流满面啊,n = (*f)(L),pmain终于在这被调用了,我们的Lua之旅终于要正式开始了……