C 可变参数函数行为不同于 Erlang 驱动程序中的预期等效代码



我替换了以下代码

(*dataset_p)[*term_count_p - 9] = ERL_DRV_ATOM;
(*dataset_p)[*term_count_p - 8] = drv->atom_error;
(*dataset_p)[*term_count_p - 7] = ERL_DRV_INT;
(*dataset_p)[*term_count_p - 6] = error_code;
(*dataset_p)[*term_count_p - 5] = ERL_DRV_STRING;
(*dataset_p)[*term_count_p - 4] = (ErlDrvTermData) error;
(*dataset_p)[*term_count_p - 3] = strlen(error);
(*dataset_p)[*term_count_p - 2] = ERL_DRV_TUPLE;
(*dataset_p)[*term_count_p - 1] = 3;

(其中dataset_p具有类型 ErlDrvTermData**term_count_pint* (

append_to_dataset(9, *dataset_p, *term_count_p,
  ERL_DRV_ATOM, drv->atom_error,
  ERL_DRV_INT, error_code,
  ERL_DRV_STRING, (ErlDrvTermData) error, strlen(error),
  ERL_DRV_TUPLE, 3);

其中append_to_dataset定义为

void append_to_dataset(int n, ErlDrvTermData* dataset, int term_count, ...) {
  int i;
  va_list new_terms;
  va_start(new_terms, term_count);
  for (i = -n; i < 0; i++) {
    dataset[term_count + i] = va_arg(new_terms, ErlDrvTermData);
  }
  va_end(new_terms);
}

(差异可以看到这就是全部差异(。在我看来,行为应该完全相同,但是当测试传递原始代码时,新版本失败并显示错误消息:

HUGE size (47278999994405)
make: *** [test] Aborted

我做错了什么?

根据第一个代码段中赋值右侧的表达式类型,这两个代码段可能不等效。

变量参数会进行默认的参数提升,但没有其他转换(与调用原型函数相反,如果参数与赋值兼容,则在必要时转换参数(。要使第二个代码正常工作,它们必须是 ErlDrvTermData 类型,而 又必须与其默认提升的类型相同,才能通过 va_arg 正确获取相应的参数。

特别是,除了前两个参数(不是变量参数(之外的每个参数都需要显式强制转换才能正确转换:

append_to_dataset(9, *dataset_p, *term_count_p,
  (ErlDrvTermData)ERL_DRV_ATOM, (ErlDrvTermData)drv->atom_error,
  (ErlDrvTermData)ERL_DRV_INT, (ErlDrvTermData)error_code,
  (ErlDrvTermData)ERL_DRV_STRING,
  (ErlDrvTermData) error, (ErlDrvTermData)strlen(error),
  (ErlDrvTermData)ERL_DRV_TUPLE, 3);

假设转换是值保留的。例如,如果ErlDrvTermDatatypedef到一个short,则必须将其作为int获取:

dataset[term_count + i] = va_arg(new_terms, int);

相关内容

最新更新