gpt4 book ai didi

c - Elixir NIF 中正确的资源处理

转载 作者:行者123 更新时间:2023-11-30 16:34:43 25 4
gpt4 key购买 nike

我正在尝试为简单的线性代数实现 NIF。这是我的矩阵内部结构:

typedef struct la_matrix {
uint rows, columns;
double **data;
} la_matrix;

这是它的“构造函数”:

la_result
la_matrix_constructor(la_matrix **res,
const uint rows,
const uint columns)
{
if (rows == 0 || columns == 0)
return dimensional_problems;

// allocate memory for meta-structure
*res = malloc(sizeof(la_matrix));
if (*res == NULL)
return null_ptr;

// allocater memory for array of pointers to rows
(*res)->data = malloc(rows * sizeof(double*));
if ((*res)->data == NULL) {
free(*res);
return null_ptr;
}

//allocate memory for each row
uint i = 0;
bool failed = false;
for (; i < rows; i++) {
(*res)->data[i] = malloc(columns * sizeof(double));
if ((*res)->data[i] == NULL) {
failed = true;
break;
}
}

if (failed) {
// one step back, since i-th row wasn't allocated
i -= 1;
for(; i < ~((uint) 0); i--)
free((*res)->data[i]);

free((*res)->data);
free(*res);
return null_ptr;
}

(*res)->rows = rows;
(*res)->columns = columns;

return ok;
}

然后我有两个 NIF 包装器——一个用于构造函数:

static ERL_NIF_TERM
nif_matrix_constructor(ErlNifEnv *env,
int argc,
const ERL_NIF_TERM *argv)
{
uint rows, columns;
enif_get_uint(env, argv[0], &rows);
enif_get_uint(env, argv[1], &columns);

la_matrix **mat_res = enif_alloc_resource(LA_MATRIX_TYPE, sizeof(la_matrix *));

la_matrix *mat_ptr;
la_result result = la_matrix_constructor(&mat_ptr, rows, columns);
if (result != ok)
return enif_make_atom(env, "err");

memcpy((void *) mat_res, (void *) &mat_ptr, sizeof(la_matrix *));

ERL_NIF_TERM term = enif_make_resource(env, mat_res);
enif_release_resource(mat_res);


return term;
}

还有一个测试构造函数是否正常工作的方法:

static ERL_NIF_TERM
nif_matrix_rows(ErlNifEnv *env,
int argc,
const ERL_NIF_TERM *argv)
{
la_matrix *mat_ptr;
if(!enif_get_resource(env, argv[0], LA_MATRIX_TYPE, (void **) &mat_ptr))
return enif_make_atom(env, "err");

return enif_make_uint(env, mat_ptr->rows);
}

看起来构造函数包装器工作得很好(我已经使用 printf 对其进行了测试),但是 nif_matrix_rows 返回了奇怪的结果,例如

iex(1)> mat = LinearAlgebra.matrix(2,3)
""
iex(2)> LinearAlgebra.rows(mat)
1677732752

直接将 LinearAlgebra.matrix(2,3) 传递给 LinearAlgebra.rows 两次会导致段错误:

iex(3)> LinearAlgebra.rows(LinearAlgebra.matrix(2,3))
1543520864
iex(4)> LinearAlgebra.rows(LinearAlgebra.matrix(2,3))
zsh: (core dumped) iex -S mix

(注意“相同”矩阵的不同结果)。

我正在关注 Andrea Leopardi 的 tutorial进行一些小的(我不太确定是否是这样)的更改来对抗 gcc 警告。恕我直言,最重要的是这部分

  la_matrix *mat_ptr;
if(!enif_get_resource(env, argv[0], LA_MATRIX_TYPE, (void **) &mat_ptr))
return enif_make_atom(env, "err");

当 Andrea Leopardi 使用时

db_conn_t **conn_res;
enif_get_resource(env, argv[0], DB_RES_TYPE, (void *) conn_res);

db_conn_t *conn = *conn_res;

但它对我来说看起来无效,因为,AFAIR,(void *) conn_res 假定 conn_res 已初始化。

这是我使用 Andrea 的方式时发生的错误:

src/nif.c: In function ‘nif_matrix_rows’:
src/nif.c:72:3: warning: ‘mat_res’ is used uninitialized in this function [-Wuninitialized]
enif_get_resource(env, argv[0], LA_MATRIX_TYPE, (void *) mat_res);

并且从 iex 调用 LinearAlgebra.rows 会导致段错误。

有人可以告诉我一种处理 NIF 中结构的正确方法吗?

附注对 C 代码感到抱歉,我从来没有写过除了一堆 helloworlds 之外的东西。

最佳答案

问题确实出在 nif_matrix_rows 中:在我的代码中,Elixir 传递了一个指向结构体 (la_matrix **) 的指针,我认为这将是一个正确的指针。

所以,快速修复是

static ERL_NIF_TERM
nif_matrix_rows(ErlNifEnv *env,
int argc,
const ERL_NIF_TERM *argv)
{
la_matrix const **mat_res;
if(!enif_get_resource(env, argv[0], LA_MATRIX_TYPE,(void **) &mat_res))
return enif_make_atom(env, "err");

la_matrix const *mat_ptr = *mat_res;

return enif_make_uint(env, mat_ptr->rows);
}

但是,我会等待一段时间以获得更优雅的解决方案,并且到目前为止不会接受这个答案。

关于c - Elixir NIF 中正确的资源处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49218499/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com