c - 函数声明中不熟悉的 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
这是我试图理解以供参考的文件。
解决方案
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
.
推荐阅读
- swift - 在类中使用协议函数
- angular - NGRX:如何从内部使用不同的有效负载多次调用相同的服务
- python - Google Slide API-我如何多次复制幻灯片并每次创建唯一的对象 ID
- reactjs - 为什么在传递给 onClick 的箭头函数中的函数调用不起作用?
- python - 使用 lambda 按姓氏对作者姓名进行排序
- html - Excel VBA宏在网站上上传文件
- java - 数据集过滤器以意想不到的方式工作
- php - 使用 Sentinel 时不支持 Redis HMGET
- mysql - 如何在 Docker 上使用与 MySQL 的加密连接
- sql - 获取 SQL Server 中每个插入的 id