【问题标题】:Using the "..." argument in functions in C with no headers在没有标题的 C 函数中使用“...”参数
【发布时间】:2018-12-29 16:26:53
【问题描述】:

我正在使用我自己的函数创建我自己的 C 库,也是为了帮助更好地理解 C,而不仅仅是依赖 GNU C 库。

到目前为止,我运行了一些函数,但我不想稍微调整我的 printo 函数以支持无限参数(仅限于字符,但您的答案也可能支持传入整数参数)。这是打印代码:

#include "../GV.h"
#include "OtherUtils.h"

int print(char *WRITEOUT1){
  char *WRITEOUT=&WRITEOUT1[0];
  int AMOUNT=GetCharSize(WRITEOUT1);

  register int SYSCALLNO asm("rax")=SYSWRITE;
  register int FD asm("rdi")=STANDARDFD;
  register char *BUF asm("rsi")=WRITEOUT;
  register int BYTES asm("rdx")=AMOUNT;
  asm("syscall");

  return 0;
}

GetCharSize 函数代码,如果有人需要的话:

#include "../GV.h" 

int GetCharSize(char *arg){
  for(i=0;arg[i]!='\0';i++){
  }
  return i;
}

GV.h 的变量定义类似于 int i;

在我问这个问题之前,我研究了像 __VA_ARGS__ 这样的 C 预处理器,但我有点无法理解它。

【问题讨论】:

  • 搜索“可变参数函数”。很多例子。 man vfprintf 一些例子。
  • 不相关,但是:1) 已经存在简约的printf 实现,您可以使用而不是重新发明轮子(printftinyprintf)。 2)下降到汇编程序级别很可能是一个巨大的矫枉过正。分析,然后优化负责 80% 运行时间的 20% 代码。其他一切都只是烧别人的钱。 3)我希望i不是GV.h里面的全局变量?
  • "GV.h 的变量定义为 int i;" - 抱歉,您这样做完全错误。该变量必须是函数内的局部变量
  • 虽然有一个 ABI,但在 C 中传递的参数是“魔法”。不可能在 C 中针对 ABI 进行编码 - 您唯一可以使用的是 C 中的可变参数函数,并且只能在 <stdarg.h> 的帮助下使用。
  • @AnttiHaapala 我能够在没有可变参数和 stdarg.h 的情况下做到这一点,哈哈

标签: c linux assembly x86-64


【解决方案1】:

... 表示法是 C 语言语法的一部分。它用于将函数的参数列表定义为最后一个参数,意思是“后跟零个或多个任何类型的参数”。例如

int printf (char *format, ...);

现在可以使用所有强制参数以及任意数量的附加参数调用以这种方式定义的函数,例如printf

以这种方式定义的函数必须能够知道有多少参数,以及每个参数的类型。 printf格式规范字符串 中知道这一点,这是 printf 唯一需要的参数。

假设 Intel 系统使用堆栈传递参数,并且参数从右向左推送(最后一个参数先推送),所以 first 可选参数将直接为 在堆栈上的格式规范字符串之后,printf 现在进行如下:获取格式规范字符串的地址并将该地址增加一个 char * 的大小。这是可选参数的开始。现在查看格式说明符字符串以了解下一个参数的类型;从堆栈中获取该类型的参数,将其增加该参数的大小以获取下一个地址。这样做直到没有更多的格式说明符为止。

【讨论】:

  • 它并没有真正帮助 OP,因为 OP 的代码针对 x86-64,并且不会使用堆栈。
  • 是的,你的解释奏效了,我真的很感激。
  • 为了从“堆栈”推广到现代调用约定,如 x86-64 System V,printf 从下一个“arg 传递槽”获取输入,无论是整数寄存器还是堆栈(如果它已经存在)经过前 6 个整数/指针参数。
猜你喜欢
  • 2020-11-11
  • 2012-03-21
  • 2019-10-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-28
相关资源
最近更新 更多