【发布时间】:2011-02-13 16:51:42
【问题描述】:
我经常看到这样声明的函数:
void Feeder(char *buff, ...)
“……”是什么意思?
【问题讨论】:
标签: c syntax function parameters
我经常看到这样声明的函数:
void Feeder(char *buff, ...)
“……”是什么意思?
【问题讨论】:
标签: c syntax function parameters
它允许可变数量的未指定类型的参数(就像printf 一样)。
您必须使用va_start、va_arg 和va_end 访问它们
更多信息请参见http://publications.gbdirect.co.uk/c_book/chapter9/stdarg.html
【讨论】:
可变参数函数是可以接受可变数量参数的函数 并用省略号代替最后一个参数声明。 这种函数的一个例子是
printf。一个典型的声明是
int check(int a, double b, ...);可变参数函数必须至少有一个命名参数,例如,
char *wrong(...);在 C 中不允许。
【讨论】:
三个点“...”称为省略号。在函数中使用它们会使该函数成为 variadic 函数。 在函数声明中使用它们意味着函数将接受已定义的参数之后的任意数量的参数。
例如:
Feeder("abc");
Feeder("abc", "def");
都是有效的函数调用,但以下不是:
Feeder();
【讨论】:
这意味着正在声明variadic function。
【讨论】:
可变函数(多参数)
#include <stdarg.h>
double average(int count, ...)
{
va_list ap;
int j;
double tot = 0;
va_start(ap, count); //Requires the last fixed parameter (to get the address)
for(j=0; j<count; j++)
tot+=va_arg(ap, double); //Requires the type to cast to. Increments ap to the next argument.
va_end(ap);
return tot/count;
}
【讨论】:
以... 作为最后一个参数的函数称为可变参数函数 (Cppreference. 2016)。这个... 用于允许具有未指定类型的可变长度参数。
当我们不确定参数的数量或其类型时,我们可以使用可变参数函数。
可变参数函数示例: 假设我们需要一个 sum 函数来返回可变数量参数的总和。我们可以在这里使用可变参数函数。
#include <stdio.h>
#include <stdarg.h>
int sum(int count, ...)
{
int total, i, temp;
total = 0;
va_list args;
va_start(args, count);
for(i=0; i<count; i++)
{
temp = va_arg(args, int);
total += temp;
}
va_end(args);
return total;
}
int main()
{
int numbers[3] = {5, 10, 15};
// Get summation of all variables of the array
int sum_of_numbers = sum(3, numbers[0], numbers[1], numbers[2]);
printf("Sum of the array %d\n", sum_of_numbers);
// Get summation of last two numbers of the array
int partial_sum_of_numbers = sum(2, numbers[1], numbers[2]);
printf("Sum of the last two numbers of the array %d\n", partial_sum_of_numbers);
return 0;
}
输出:
练习题:练习变参函数的简单题可以在hackerrank practice problem here
参考:
【讨论】:
... = 三点 = 三点 = 调用:ellipsis
...参数的函数被调用:Variadic function
int validFunctionWithNamedParameterThenEllipsis(int a, double b, ...);int invalidFunctionOnlyEllipsis(...);热门案例:
int printf(const char *format, ...)
呼叫:
printf("year=%d, name=%s", 2021, "crifan");
->
format == "year=%d, name=%s"
... == 2021, "crifan"
2021
"crifan"
va_list,与va_start,va_arg,va_end
#include <stdarg.h>
void va_start(va_list ap, last_arg);
type va_arg(va_list ap, type);
void va_end(va list ap);
#include <stdarg.h>
#include <stdio.h>
double average(int count, ...) {
va_list ap;
int j;
double sum = 0;
va_start(ap, count); /* Requires the last fixed parameter (to get the address) */
for (j = 0; j < count; j++) {
sum += va_arg(ap, int); /* Increments ap to the next argument. */
}
va_end(ap);
return sum / count;
}
int main(int argc, char const *argv[]) {
printf("%f\n", average(3, 1, 2, 3));
return 0;
}
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>
int maxof(int, ...) ;
void f(void);
main(){
f();
exit(EXIT_SUCCESS);
}
int maxof(int n_args, ...){
register int i;
int max, a;
va_list ap;
va_start(ap, n_args);
max = va_arg(ap, int);
for(i = 2; i <= n_args; i++) {
if((a = va_arg(ap, int)) > max)
max = a;
}
va_end(ap);
return max;
}
void f(void) {
int i = 5;
int j[256];
j[42] = 24;
printf("%d\n",maxof(3, i, j[42], 0));
}
#include <stdarg.h>
#define MAXARGS 31
/*
* execl is called by
* execl(file, arg1, arg2, ..., (char *)(0));
*/
int execl(const char *file, const char *args, ...)
{
va_list ap;
char *array[MAXARGS +1];
int argno = 0;
va_start(ap, args);
while (args != 0 && argno < MAXARGS)
{
array[argno++] = args;
args = va_arg(ap, const char *);
}
array[argno] = (char *) 0;
va_end(ap);
return execv(file, array);
}
/*==============================================================================
Hook: syscall()
==============================================================================*/
int syscall(int, ...);
// normally max number of syscall parameter is not exceed 8
// refer: https://opensource.apple.com/source/xnu/xnu-4570.1.46/bsd/kern/syscalls.master
int MaxSupportArgNum_syscall = 16;
%hookf(int, syscall, int number, ...){
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: number=%d", number);
// Setting up some variables to get all the parameters from syscall
void *paraPtr, *paraList[MaxSupportArgNum_syscall];
// char *paraPtr, *paraList[MaxSupportArgNum_syscall];
va_list argList;
int curParaNum = 0;
va_start(argList, number);
while ((paraPtr = (void *) va_arg(argList, void *))) {
// while ((paraPtr = (char *) va_arg(argList, char *))) {
paraList[curParaNum] = paraPtr;
curParaNum += 1;
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: [%d] paraPtr=%p", curParaNum, paraPtr);
}
va_end(argList);
// os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: argList=%{public}s", argList);
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: curParaNum=%d", curParaNum);
bool isStat = (SYS_stat == number);
bool isStat64 = (SYS_stat64 == number);
if (isStat || isStat64){
char* curPath = (char *)paraList[0];
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: isStat=%{bool}d, isStat64=%{BOOL}d, curPath=%{public}s", isStat, isStat64, curPath);
bool isJbPath = isJailbreakPath(curPath);
if (isJbPath){
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: IS jailbreak path: %{public}s", curPath);
return OPEN_FAILED;
} else {
os_log(OS_LOG_DEFAULT, "hook_syscall_stat_stat64: NOT jailbreak path: %{public}s", curPath);
}
}
// return %orig;
// return %orig(number, ...);
// int retValue = %orig();
// int retValue = callOriginSyscall(number, curParaNum, paraList);
//// int retValue = callOriginSyscall(number, curParaNum, (void *)paraList);
// os_log(OS_LOG_DEFAULT, "hook_syscall_stat_file: retValue=%d", retValue);
// return retValue;
int paraNum = curParaNum;
int syscallRetValue = -1;
if (0 == paraNum){
syscallRetValue = %orig(number);
} else if (1 == paraNum){
void* para1 = paraList[0];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p", para1);
syscallRetValue = %orig(number, para1);
} else if (2 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p", para1, para2);
syscallRetValue = %orig(number, para1, para2);
} else if (3 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p", para1, para2, para3);
syscallRetValue = %orig(number, para1, para2, para3);
} else if (4 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p", para1, para2, para3, para4);
syscallRetValue = %orig(number, para1, para2, para3, para4);
} else if (5 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p,para5=%p", para1, para2, para3, para4, para5);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5);
} else if (6 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p", para1, para2, para3, para4, para5, para6);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6);
} else if (7 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
void* para7 = paraList[6];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p,para7=%p", para1, para2, para3, para4, para5, para6, para7);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6, para7);
} else if (8 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
void* para7 = paraList[6];
void* para8 = paraList[7];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p,para7=%p,para8=%p", para1, para2, para3, para4, para5, para6, para7, para8);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6, para7, para8);
} else if (9 == paraNum){
void* para1 = paraList[0];
void* para2 = paraList[1];
void* para3 = paraList[2];
void* para4 = paraList[3];
void* para5 = paraList[4];
void* para6 = paraList[5];
void* para7 = paraList[6];
void* para8 = paraList[7];
void* para9 = paraList[8];
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: para1=%p,para2=%p,para3=%p,para4=%p,para5=%p,para6=%p,para7=%p,para8=%p,para9=%p", para1, para2, para3, para4, para5, para6, para7, para8, para9);
syscallRetValue = %orig(number, para1, para2, para3, para4, para5, para6, para7, para8, para9);
}
os_log(OS_LOG_DEFAULT, "hook_syscall_orig: syscallRetValue=%d", syscallRetValue);
return syscallRetValue;
}
当调用va_start时,last_arg是最后一个命名的参数,而不是第一个
发给:int open(const char *path, int oflag, ...);
va_start(argList, oflag);va_start(argList, path);
Second argument to 'va_start' is not the last named parametertype va_arg(va_list ap, type);
对于通过type,有一种特殊情况:
传入时:
但返回总是:
-> 所以当代码:
curPara = (mode_t) va_arg(argList, mode_t);
根据:
#include <sys/stat.h>
#include <sys/types.h>
->mode_t==unsigned short
相当于:
curPara = (mode_t) va_arg(argList, unsigned short);
所以编译器警告:
Second argument to 'va_arg' is of promotable type 'mode_t' (aka 'unsigned short'); this va_arg has undefined behavior because arguments will be promoted to 'int'
改为:
curPara = (mode_t) va_arg(argList, unsigned int);
可以避免警告。
【讨论】: