programing

C 함수 선언에서 "..."는 마지막 매개 변수로서 무엇을 합니까?

prostudy 2022. 9. 4. 12:29
반응형

C 함수 선언에서 "..."는 마지막 매개 변수로서 무엇을 합니까?

다음과 같이 선언된 함수를 자주 볼 수 있습니다.

void Feeder(char *buff, ...)

"..."이 무슨 뜻입니까?

지정되지 않은 유형의 변수 수가 허용됩니다(예:printf하고 있습니다).

접속할 수 있도록va_start,va_arg그리고.va_end

상세한 것에 대하여는, http://publications.gbdirect.co.uk/c_book/chapter9/stdarg.html 를 참조해 주세요.

variadic 함수(변수 파라미터)

위키

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

기능...마지막 매개변수를 Varadic 함수라고 합니다(Cppreference. 2016).이것....는 지정되지 않은 유형의 가변 길이 파라미터를 허용하기 위해 사용합니다.

파라미터의 수나 타입이 불분명한 경우에는 바리에타디 함수를 사용할 수 있습니다.

가변 함수의 예:변수 개수의 합계를 반환하는 합함수가 필요하다고 가정합시다.여기서는 가변 함수를 사용할 수 있습니다.

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

출력:

C출력

연습 문제:가변 함수를 연습하기 위한 간단한 문제는 여기 해커랭크 연습 문제에서 찾을 수 있습니다.

레퍼런스:

  • cppreference.(2016년 2월 13일).가변 함수https://en.cppreference.com/w/c/variadic에서 2018년 7월 25일 취득

가변 함수

변수 함수는 변수 개수의 인수를 사용할 수 있으며 마지막 매개 변수 대신 줄임표로 선언되는 함수입니다.이러한 함수의 예는 다음과 같습니다.printf.

일반적인 선언은

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

변수 함수에는 적어도 하나의 명명된 매개 변수가 있어야 합니다. 예를 들어 다음과 같습니다.

    char *wrong(...);  

C에서는 사용할 수 없습니다.

세 개의 점 '...'을 줄임표라고 한다.함수에서 이들을 사용하면 해당 함수는 가변 함수가 됩니다.함수 선언에서 이러한 파라미터를 사용한다는 것은 함수가 이미 정의된 파라미터 뒤에 임의의 수의 파라미터를 받아들인다는 것을 의미합니다.

예를 들어 다음과 같습니다.

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

는 모두 유효한 함수 호출입니다.단, 다음과 같습니다.

Feeder();

이것은 가변 함수가 선언되고 있음을 의미합니다.

  • ...= 3점 = 3점 = 호출됨:ellipsis
    • 평균: 변수 수 모수
      • 일반 함수와 비교: 고정(지정된 수) 매개 변수
  • 와 기능하다....para는 다음과 같습니다.가변 함수

가변 함수

정의.

  • 유효:
    • 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"
    • 변수 수
      • 여기서 total 2 파라미터
        • : first : " " "2021
        • : 유형 " " " " ""crifan"

Varadic 함수의 파레미터 취득/계산 방법

  • 로직:: 사용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()

/*==============================================================================
 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) ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★」
        • Second argument to 'va_start' is not the last named parameter

va_module

type va_arg(va_list ap, type);

type하다

전달 시:

  • 부호 없는 문자
  • 부호 없는 쇼트

단, 반환은 항상 다음과 같습니다.

  • 부호 없는 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);

경고를 피할 수 있습니다.

관련 문서

언급URL : https://stackoverflow.com/questions/2735587/in-a-c-function-declaration-what-does-as-the-last-parameter-do

반응형