Незнакомый синтаксис C в объявлении функции - PullRequest
0 голосов
/ 18 ноября 2018

В настоящее время я смотрю на некоторый C-код, который не имеет никакого смысла для меня. Что такое (elementSize)? Как передать аргументы этой статической функции? Как называется этот стиль синтаксиса, чтобы я мог больше узнать о нем?

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

Это файл, который я пытаюсь понять для справки.

1 Ответ

0 голосов
/ 18 ноября 2018

Обычно

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"

с TH_CONCAT_..., определенным в 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)

Таким образом, 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 для поплавки действительно называются torch_floatTensor_elementSize).

Все, что мы действительно пытаемся сделать, это абстрагироваться от параметра типа, который здесь называется Real.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...