2012-05-18 45 views
15

我想写一个返回类型为va_list的函数。在C中返回va_list安全吗?

例如:va_list MyFunc(va_list args);

这是安全和便携式?

+4

如果你的意图是传入'va_list',修改它,然后在函数返回时使用修改过的'va_list',最好考虑将指向'va_list'的指针传递给'MyFunct() '并通过指针使其在列表上起作用。该标准特别提到脚注允许使用该技术。 –

+0

这正是我的意图。你能指出标准的地方吗? –

+2

在我看来,'va_list'是一个坏主意。通常有更好的解决方案更安全。所以我会认真思考,并为该功能的设计和实现提供更好的解决方案。 –

回答

6

va_list可能(但不能保证)是一个数组类型,所以您无法按值传递或返回它。看起来好像它的代码可能只是传递/返回指向第一个元素的指针,所以您可以在被调用者中使用该参数,但是您可能会在原始代码上执行该操作。

形式上你可以说va_list是一个实体类型,而不是一个值类型。您将其复制为va_copy,而不是通过赋值或通过函数参数/返回。

1

虽然你绝对可以return这样一个值,我不知道是否可以用有用的方式使用返回值。

由于va_list S上的处理需要特殊处理(va_start()va_copy()后需要va_end()),以及va_start/copyva_end宏甚至允许包含{ }执行这一配对,你不能说一个没有其他。

+3

'va_copy'用于创建* second *'va_list'对象,该对象可以独立于原始对象进行读取。由于这不是这种情况,所以我会说可以传递并返回'va_list'对象。此外,该标准没有提到'va_start()'和'va_end()'必须在同一个范围内,因此我不知道它们如何被允许包含'{':es。 – Lindydancer

+2

@Lindydancer哦,不知道。 [Here](http://linux.die.net/man/3/va_start)我读到“每次调用va_start()都必须匹配va_end()在相同函数中的相应调用”和“每次调用va_copy()必须在相同的函数中匹配va_end()的相应调用。“,所以我认为它是从标准锥... – glglgl

+0

@glglgl:”在同一个函数中“并不一定意味着”在同样的范围“,所以并不意味着宏可以使用不匹配的大括号。但它确实允许'va_copy'使用像'alloca'这样的技巧,因为新列表不会超出函数返回的范围。 –

1

无论语言标准如何,这在实践中都不太可能发挥作用。 A va_list很可能是指向由呼叫者放置在堆栈上的呼叫记录的指针,以便为被呼叫者带来利益。一旦被调用者返回,堆栈中的内存是公平的游戏以供重用。

返回类型va_list不太可能实际上将列表内容复制回调用者。尽管这将是C的有效实现,但如果标准要求这样做,那么这将成为规范中的缺陷。

+0

“va_end”宏存在的原因正是因为'va_list'不一定只是指向堆栈上的某个指针。否则,'va_end'将永远是空操作。存在'va_list'对象在堆上分配的实现。 –

+0

@DietrichEpp好信息,我以为'va_end'有一些注册窗口或旧的实现,只允许一次迭代器。调整了我的答案,但这只是一个相对重点问题......大多数架构不会使用可变参数堆。 – Potatoswatter

0

传递指向另一个函数的指针与返回该指针的 完全不同。许多/大多数实现将 实际变量参数存储在栈帧中,该栈帧在可变参数函数返回时被破坏。 (即返回一个va_list或一个指向 的指针,会给你指向局部变量的指针,这些指针被破坏) 。 - 第

在我的情况

好,我会为警告返回的va_list回来,但感谢 - Hayri维吾尔族如果你传递一个指向va_list的功能MyFunc(va_list *args) Koltuk

,你不需要将修改后的(由va_arg(*args, type))参数列表传回,因为MyFunc修改了原始列表。

+0

我不认为它是指定'MyFunc'是否修改原始列表。我当然遇到了两种工作方式的实现。 – supercat

+0

@supercat - 如果指向任何对象的指针被传递给函数,并且该函数修改指向的对象,则固有原始对象被修改。 – Armali

+0

如果一个va_list是一个简单的指针(在许多平台上最为有效),将它传递给一个函数会给函数一个指针的副本,并且va_arg会增加指针的副本而不会影响原始指针。 – supercat