如何在C中实现stdarg

sad*_*jfh 5 c header-files

为了好奇,我想为标准C库中的一些函数编写最小的替换.到目前为止,我已经完成了printf(),strlen(),strcpy(),memcpy(),memset(),等...但是当我尝试使用printf函数,我不知道如何实现stdarg.h!我能做到这一点的方式是什么?

它是使用宏还是实际功能?

我在32位x86上使用gccOR clang,如果它有助于使这更容易回答.

ick*_*fay 7

在使用 cdecl 调用约定的 32 位 x86 上,参数在堆栈上传递:

\n\n
^ higher addresses (lower on the stack)\n|\n| caller local variables\n| ...\n| argument 3\n| argument 2\n| argument 1\n| return address\n| saved EBP (usually)\n| callee local variables\n|\nv lower addresses (higher on the stack)\n
Run Code Online (Sandbox Code Playgroud)\n\n

您可以将其实现va_list为指针。va_start可以获取传递给它的参数的地址并添加该参数的大小以移动到下一个参数。va_arg可以访问指针并将其碰撞到下一个参数。va_copy可以只复制指针值。va_end\xe2\x80\x99 不需要做任何事情。

\n\n

另一方面,如果您\xe2\x80\x99没有使用cdecl(也许您\xe2\x80\x99正在使用fastcall),则您\xe2\x80\x99不是32位,您\xe2\x80\x99不是32位x86,这不会 \xe2\x80\x99 工作;您可能需要处理寄存器而不仅仅是指针值。即使如此,它仍然不能保证工作,因为你依赖于未定义的行为;作为唯一一个潜在问题的例子,内联可能会毁掉一切。这就是为什么头文件只是typedef将其发送到内置编译器 xe2x80x94 在 C 中实现这一点是没有希望的,您需要编译器支持。并且不要\xe2\x80\x99t甚至让我开始实现setjmplongjmp\xe2\x80\xa6

\n

  • 这个答案是错误的;它假设古老的编译器技术,其中参数对象的地址实际上是它们在堆栈上传递的地址。没有理由需要这样。即使在像 i386 这样的体系结构上,外部函数的参数在堆栈上传递,编译器也可以完全自由地将它们移动到单独的本地存储,并让“&”生成指向该新存储的指针。它还可以自由地执行内联/LTO,在这种情况下,参数可能根本不会存在于堆栈中。 (2认同)