在C函数声明中,“,..”作为最后一个参数吗?

xkftehaa  于 2023-04-29  发布在  其他
关注(0)|答案(7)|浏览(165)

我经常看到这样的函数声明:

void Feeder(char *buff, ...)

什么做”。”是什么意思

twh00eeo

twh00eeo1#

它允许未指定类型的变量数量(如printf)。
您必须使用va_startva_argva_end函数访问参数。
有关详细信息,请参见http://publications.gbdirect.co.uk/c_book/chapter9/stdarg.htmlWhere in the C standard variadic functions are described?

ibrsph3r

ibrsph3r2#

变分函数
可变参数函数是可以采用可变数量的参数的函数,并且用省略号代替最后一个参数来声明。这种函数的一个例子是printf
一个典型的声明是

int check(int a, double b, ...);

变量函数必须至少有一个命名参数,例如,

char *wrong(...);

在C中不允许。

hwamh0ep

hwamh0ep3#

变元函数(多参数)
维基

#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;
}
jhkqcmku

jhkqcmku4#

三个点。..'被称为省略号。在函数中使用它们会使该函数成为一个变量函数。在函数声明中使用它们意味着函数将接受已定义参数之后的任意数量的参数。
例如:

Feeder("abc");
Feeder("abc", "def");

都是有效的函数调用,但以下不是:

Feeder();
9rnv2umw

9rnv2umw5#

这意味着正在声明一个可变参数函数。

brgchamk

brgchamk6#

...作为最后一个参数的函数称为变分函数(Cppreference)。这个...用于允许具有未指定类型的可变长度参数。
当我们不确定参数的数量或类型时,可以使用可变参数函数。

**变量函数示例:**假设我们需要一个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中找到
参考:

gblwokeq

gblwokeq7#

  • ... =三个点=三个点=调用:ellipsis
  • 表示:变量参数个数
  • 与正常功能相比:固定(命名个数)参数
  • 使用...帕拉调用函数:变分函数

变元函数

定义

  • 有效期:
  • 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"
  • 可变参数数
  • 此处共有2个参数
  • 第一个:整数类型2021
  • second:string type "crifan"

如何获取/计算Variadic函数的参数

  • 核心逻辑:使用va_list,搭配va_startva_argva_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;
}
maxof
#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()
/*==============================================================================
 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

当调用va_start时,last_arg是最后一个命名的参数,而不是第一个
适用于:int open(const char *path, int oflag, ...);

  • 改正
  • va_start(argList, oflag);
  • va_start(argList, path);
  • (XCode的clang)编译器将警告
  • Second argument to 'va_start' is not the last named parameter
va_arg

type va_arg(va_list ap, type);
对于pass type,存在特殊情况:
传入时:

  • 无符号字符
  • 无符号短

但return总是:

*unsigned int

  • 〉当代码:
    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);
    可以避免警告。

相关单据

相关问题