首页 > 解决方案 > 函数声明中不熟悉的 C 语法

问题描述

目前正在查看一些对我没有任何意义的 C 代码。什么是(元素大小)?应该如何将参数传递给这个静态函数?这种语法风格的名称是什么,以便我可以了解更多关于它的信息?

static int torch_Tensor_(elementSize)(lua_State *L)
{
  luaT_pushinteger(L, THStorage_(elementSize)());
  return 1;
}

https://github.com/torch/torch7/blob/master/generic/Tensor.c

这是我试图理解以供参考的文件。

标签: cfunction

解决方案


Normally

static int torch_Tensor_(elementSize)(lua_State *L)

would mean torch_Tensor_ is a function that takes a single parameter called elementSize that has no type (?! - syntax error) and returns a function that takes a pointer to lua_State and returns an int. This is blatantly invalid (functions cannot return other functions).

But what's actually going on here is that torch_Tensor_ is defined as a function-like macro, so before the compiler even sees this declaration, torch_Tensor_(elementSize) is replaced by something else.

In https://github.com/torch/torch7/blob/master/Tensor.c there is

#include "general.h"

#define torch_Storage_(NAME) TH_CONCAT_4(torch_,Real,Storage_,NAME)
#define torch_Storage TH_CONCAT_STRING_3(torch.,Real,Storage)
#define torch_Tensor_(NAME) TH_CONCAT_4(torch_,Real,Tensor_,NAME)
#define torch_Tensor TH_CONCAT_STRING_3(torch.,Real,Tensor)

#include "generic/Tensor.c"
#include "THGenerateAllTypes.h"

#include "generic/Tensor.c"
#include "THGenerateHalfType.h"

with TH_CONCAT_... defined in lib/TH/THGeneral.h.in:

#define TH_CONCAT_STRING_3(x,y,z) TH_CONCAT_STRING_3_EXPAND(x,y,z)
#define TH_CONCAT_STRING_3_EXPAND(x,y,z) #x #y #z

#define TH_CONCAT_4_EXPAND(x,y,z,w) x ## y ## z ## w
#define TH_CONCAT_4(x,y,z,w) TH_CONCAT_4_EXPAND(x,y,z,w)

So torch_Tensor_ is defined as a macro before generic/Tensor.c is included.

torch_Tensor_(elementSize)

expands to

TH_CONCAT_4(torch_,Real,Tensor_,elementSize)

which expands to

TH_CONCAT_4_EXPAND(torch_,...,Tensor_,elementSize)

... is a placeholder, not real code. Real is defined as a macro in the various THGenerate*Type.h files, so this line actually becomes

TH_CONCAT_4_EXPAND(torch_,char,Tensor_,elementSize)
TH_CONCAT_4_EXPAND(torch_,int,Tensor_,elementSize)
TH_CONCAT_4_EXPAND(torch_,float,Tensor_,elementSize)
...

depending on context. Anyway, the end result is a single identifier of the form

torch_charTensor_elementSize
torch_intTensor_elementSize
torch_floatTensor_elementSize
...

(one token).

The resulting function definition thus looks like e.g.

static int torch_charTensor_elementSize(lua_State *L)
{
    ...
}

depending on which context generic/Tensor.c was included in.

The reason things are done this way is to have what amounts to the same code, but for multiple different types. In C++ you would write a function template:

namespace torch {
    template<typename Real>
    static int Tensor_elementSize(lua_State *L) { ... }
}

But C has no templates (nor namespaces), so the only way to get "generic" code like this is to do it manually with macros and preprocessing tricks (and manually "decorating" names; e.g. the elementSize function for floats is really called torch_floatTensor_elementSize).

All we're really trying to do is abstract over a type parameter, here called Real.


推荐阅读