使用va_list和va_arg实现子功能

fea*_*ool 1 c variadic-functions

我有一个varargs样式的函数,我想拆分为va_list样式的子函数。原始功能:

void container_append(container_t *c, element_t *element, ...) {
  element_t *e;
  va_list ap;

  va_start(ap, element);
  while((e = va_arg(ap, element_t *)) != NULL) {
    container_append_aux(c, e);
  }
  va_end(ap);
}
Run Code Online (Sandbox Code Playgroud)

请注意,调用者必须以NULL终止元素列表,但这不会引起任何问题。重构:

void container_append(container_t *c, element_t *element, ...) {
  va_list ap;
  va_start(ap, element);
  container_vappend(c, ap);
  va_end(ap);
}

void container_vappend(container_t *c, va_list ap) {
  element_t *e;
  while ((e = va_arg(ap, element_t *)) != NULL) {
    container_append_aux(c, e);
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,当我这样称呼它时:

container_append(c, NULL);
Run Code Online (Sandbox Code Playgroud)

...内container_vappend()的呼叫传va_arg()回非NULL的值。

这是一个更复杂的函数的抄写,但是除非有任何错别字,否则我在设置和使用va_listand时错过了什么va_arg()吗?

chu*_*ica 5

除了由@zwol确定的好 ...

container_append(c, one or more arguments, NULL);是潜在的不确定行为(UB)。

container_append()期望一个element_t *element并且NULL可能很简单0

NULL 扩展为实现定义的空指针常量...

值为0的整数常量表达式或转换为类型的表达式 void *称为空指针常量

NULL 甚至没有指定与指针相同的大小。

va_arg(ap, element_t *) 然后是UB。

为了拨打更安全的电话,请使用 container_append(c, args, (element_t *) NULL);

  • @ user3386109使用foo(some_object * p);使用foo(NULL);可以作为NULL转换为指针。使用`container_append(c,some args,NULL)`,`NULL'不会被转换,因此它会以其原始类型的值传递,例如`int`。`container_append(container_t * c,element_t * element,...)`并不知道其定义将使用...参数(例如NULL)作为指针。 (2认同)