【问题标题】:Unfamiliar C Syntax in the Declaration of Function函数声明中不熟悉的 C 语法
【发布时间】:2018-11-17 23:10:40
【问题描述】:

目前正在查看一些对我来说没有任何意义的 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

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

【问题讨论】:

  • torch_Tensor_THStorage_ 可能是宏。 THStorage_ 可能是一个返回函数指针的函数。
  • 单独取,只是语法错误。您可以定义返回指向函数的指针的函数(例如标准 C 中的 signal()),但不能定义返回函数的函数(也不能定义返回数组而不是指针的函数)。如果有一些宏可以提供帮助(例如#define torch_Tensor_(x) …,那么它可能会编译,并且您需要确定elementSize 的定义位置以了解作为参数传递给宏的内容。看起来您需要研究 Lua 提供的头文件。

标签: c function


【解决方案1】:

正常

static int torch_Tensor_(elementSize)(lua_State *L)

意味着torch_Tensor_ 是一个函数,它接受一个名为elementSize 的没有类型的参数(?!- 语法错误)并返回一个函数,该函数接受一个指向lua_State 的指针并返回一个int。这是公然无效的(函数不能返回其他函数)。

但这里实际发生的是 torch_Tensor_ 被定义为类似函数的宏,所以在编译器甚至看到这个声明之前,torch_Tensor_(elementSize) 就被其他东西替换了。

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

#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"

lib/TH/THGeneral.h.in 中定义TH_CONCAT_...

#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)

所以 torch_Tensor_ 在包含 generic/Tensor.c 之前被定义为宏。

torch_Tensor_(elementSize)

扩展到

TH_CONCAT_4(torch_,Real,Tensor_,elementSize)

扩展为

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

... 是占位符,不是真正的代码。 Real在各种THGenerate*Type.h文件中被定义为宏,所以这一行实际上变成了

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

取决于上下文。无论如何,最终结果是表单的单个标识符

torch_charTensor_elementSize
torch_intTensor_elementSize
torch_floatTensor_elementSize
...

(一个令牌)。

生成的函数定义因此看起来像例如

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

取决于 generic/Tensor.c 包含在哪个上下文中。

这样做的原因是拥有相同的代码,但用于多种不同的类型。在 C++ 中,您将编写一个函数模板:

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

但是 C 没有模板(也没有命名空间),因此获得像这样的“通用”代码的唯一方法是使用宏和预处理技巧手动完成(并手动“装饰”名称;例如 elementSize 函数floats 真的叫torch_floatTensor_elementSize)。

我们真正想做的只是对类型参数进行抽象,这里称为Real

【讨论】:

  • 我猜该文件被编译多次,elementSize 被定义为不同的值。例如,如果您将其定义为 8,您最终会得到 torch_RealTensor_8()
  • @nemequ 不,参数是RealelementSize 是函数的名称。
  • 非常感谢您的指导!这很有帮助,我会仔细检查以确保我理解所有内容。
  • 哇,我终于坐下来消化了你写的指南。现在终于有了很大的意义。我仍然感到困惑的唯一一件事是编译器如何知道 Real 是宏定义的变量,而不是以下代码 TH_CONCAT_4(torch_,Real,Tensor_,elementSize) 中的 Tensor_ 或 elementSize?
  • @btomtom5 预处理器只是对所有标识符执行宏扩展。原则上,所有这些名称都可以是 #defined 或者其他名称,但快速搜索代码库显示只有 #define Real ... 出现在某些文件中,所以这就是预处理器替换的内容。当然,我假设generic/Tensor.c 仅包含在#define Real ... 处于活动状态的地方;否则它将保持原样。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-15
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多