将经过默认参数提升的对象传递给“va_start”

Posted

技术标签:

【中文标题】将经过默认参数提升的对象传递给“va_start”【英文标题】:Passing an object that undergoes default argument promotion to 'va_start' 【发布时间】:2019-10-09 09:09:23 【问题描述】:

这是我的第一个 Xcode 应用程序和 Objective-c,所以请给我一些放松 :)

我尝试在谷歌上搜索该问题,但我看不到有关 Xcode 和应用程序开发的任何帮助。我在 //

之后添加了错误按摩
- (id)initWithBytes:(int8_t)byte1, ...  //Error: 1. Parameter of type 'int8_t' (aka 'signed char') is declared here
  va_list args;
  va_start(args, byte1); //Error: Passing an object that undergoes default argument promotion to 'va_start' has undefined behavior
  unsigned int length = 0;
  for (int8_t byte = byte1; byte != -1; byte = va_arg(args, int)) 
    length++;
  
  va_end(args);

  if ((self = [self initWithLength:length]) && (length > 0)) 
    va_list args;
    va_start(args, byte1); // Error: Passing an object that undergoes default argument promotion to 'va_start' has undefined behavior
    int i = 0;
    for (int8_t byte = byte1; byte != -1; byte = va_arg(args, int)) 
      _array[i++] = byte;
    
    va_end(args);
  
 return self;

提前谢谢你!!

【问题讨论】:

哇,这很复杂。为什么不传递uint8_ts 和长度的数组? @***foe 希望我知道如何 :) 我太新了,无法理解我的代码的作用。 很少使用可变参数。您通常只会看到它们用于记录/打印(请参阅 NSLog()printf()),所以请扔掉它们。如果你想传递一个字符/字节数组,那么传递一个指针和一个长度,这足以描述数组。例如:- (nonnull instancetype)initWithBuffer:(const uint_t *)buffer ofLength:(NSUInteger)length ... ;。事实上,这几乎就是 NSData 类所做的事情,所以你可能应该改用它。显示类声明,我会提供正确的答案。 我不知道为什么va_start 不喜欢int8_t,尝试使用其他类型。顺便说一句,你想达到什么目的? 我尝试了int8_t的几个选项,但仍然出现错误。你建议我用哪一个? @Cy-4AH 【参考方案1】:

va_start() 将指向传递给函数的第一个参数的指针保存到va_list 中。 参数本身通过硬件堆栈传递。

int8_t 的问题来自于硬件堆栈的实现方式。 (至少在 x86 中)

就像 SSE 和 MMX 一样,堆栈要求存储在其上的元素对齐等于 16 位的倍数,因此传递给函数的所有内容都将具有至少 16 位大小,无论其类型如何。

但问题是va_arg() 不知道这一切。从历史上看,它是一个宏,它所做的只是返回一个存储在va_list 中的指针,并将va_list 递增sizeof(type)

因此,当您检索下一个参数时,返回的指针不指向下一个参数,而是指向它之前的一个字节 - 取决于 va_arg 是宏还是编译器内置函数。

这就是警告的含义。

至少是国际海事组织。请原谅我的英语,这是我的第二语言。

【讨论】:

我对objective-C一无所知,但这个答案对我来说是正确的。以下是支持这一点的 C/C++ 中一些更详细的示例。 wiki.sei.cmu.edu/confluence/display/cplusplus/…

以上是关于将经过默认参数提升的对象传递给“va_start”的主要内容,如果未能解决你的问题,请参考以下文章

怎么将可变参数的函数的参数传递给另一个可变参数的函数

将 unicode 参数传递给 ShellExecuteEx 中的子进程

将默认列表参数传递给数据类

将默认参数传递给python中的装饰器

有条件地将任意数量的默认命名参数传递给函数

对象作为参数传递给另一个类,通过值还是引用?