변수 개수의 인수 전달
변수 개수의 인수를 사용하는 C 함수가 있다고 가정합니다.첫 번째 함수에 들어간 모든 인수를 전달하면서 내부에서 가변 개수의 인수를 예상하는 다른 함수를 호출하려면 어떻게 해야 합니까?
예:
void format_string(char *fmt, ...);
void debug_print(int dbg_lvl, char *fmt, ...) {
format_string(fmt, /* how do I pass all the arguments from '...'? */);
fprintf(stdout, fmt);
}
줄임표를 전달하려면va_list
두 번째 기능에 전달하기만 하면 됩니다.사용 안 함va_arg()
구체적으로는
void format_string(char *fmt,va_list argptr, char *formatted_string);
void debug_print(int dbg_lvl, char *fmt, ...)
{
char formatted_string[MAX_FMT_SIZE];
va_list argptr;
va_start(argptr,fmt);
format_string(fmt, argptr, formatted_string);
va_end(argptr);
fprintf(stdout, "%s",formatted_string);
}
장난꾸러기나 휴대하기 어려운 속임수를 쓰고 싶지 않다면, 당신이 얼마나 많은 논쟁을 하고 있는지 모르는 상태에서 printf에 전화를 걸 수 있는 방법은 없습니다.
일반적으로 사용되는 솔루션은 항상 vararg 함수의 대체 형식을 제공하는 것입니다.printf
가지다vprintf
이 방법에는va_list
대신...
.그...
버전들은 단지 랩퍼일 뿐입니다.va_list
를 참조해당 버전.
먼저 포메터를 로컬버퍼에 저장함으로써 포메터를 통과하는 문제를 해결할 수 있지만, 이는 스택이 필요하며 경우에 따라서는 처리해야 할 문제가 될 수 있습니다.팔로잉을 해봤는데 잘 되는 것 같아요.
#include <stdarg.h>
#include <stdio.h>
void print(char const* fmt, ...)
{
va_list arg;
va_start(arg, fmt);
vprintf(fmt, arg);
va_end(arg);
}
void printFormatted(char const* fmt, va_list arg)
{
vprintf(fmt, arg);
}
void showLog(int mdl, char const* type, ...)
{
print("\nMDL: %d, TYPE: %s", mdl, type);
va_list arg;
va_start(arg, type);
char const* fmt = va_arg(arg, char const*);
printFormatted(fmt, arg);
va_end(arg);
}
int main()
{
int x = 3, y = 6;
showLog(1, "INF, ", "Value = %d, %d Looks Good! %s", x, y, "Infact Awesome!!");
showLog(1, "ERR");
}
이게 도움이 됐으면 좋겠다.
단답
/// logs all messages below this level, level 0 turns off LOG
#ifndef LOG_LEVEL
#define LOG_LEVEL 5 // 0:off, 1:error, 2:warning, 3: info, 4: debug, 5:verbose
#endif
#define _LOG_FORMAT_SHORT(letter, format) "[" #letter "]: " format "\n"
/// short log
#define log_s(level, format, ...) \
if (level <= LOG_LEVEL) \
printf(_LOG_FORMAT_SHORT(level, format), ##__VA_ARGS__)
사용.
log_s(1, "fatal error occurred");
log_s(3, "x=%d and name=%s",2, "ali");
산출량
[1]: fatal error occurred
[3]: x=2 and name=ali
파일 및 행 번호를 포함한 로그
const char* _getFileName(const char* path)
{
size_t i = 0;
size_t pos = 0;
char* p = (char*)path;
while (*p) {
i++;
if (*p == '/' || *p == '\\') {
pos = i;
}
p++;
}
return path + pos;
}
#define _LOG_FORMAT(letter, format) \
"[" #letter "][%s:%u] %s(): " format "\n", _getFileName(__FILE__), __LINE__, __FUNCTION__
#ifndef LOG_LEVEL
#define LOG_LEVEL 5 // 0:off, 1:error, 2:warning, 3: info, 4: debug, 5:verbose
#endif
/// long log
#define log_l(level, format, ...) \
if (level <= LOG_LEVEL) \
printf(_LOG_FORMAT(level, format), ##__VA_ARGS__)
사용.
log_s(1, "fatal error occurred");
log_s(3, "x=%d and name=%s",2, "ali");
산출량
[1][test.cpp:97] main(): fatal error occurred
[3][test.cpp:98] main(): x=2 and name=ali
커스텀 프린트 기능
커스텀 프린트 기능을 쓰고 패스할 수 있습니다....
args를 사용하여 위의 메서드와 결합할 수도 있습니다.
int print_custom(const char* format, ...)
{
static char loc_buf[64];
char* temp = loc_buf;
int len;
va_list arg;
va_list copy;
va_start(arg, format);
va_copy(copy, arg);
len = vsnprintf(NULL, 0, format, arg);
va_end(copy);
if (len >= sizeof(loc_buf)) {
temp = (char*)malloc(len + 1);
if (temp == NULL) {
return 0;
}
}
vsnprintf(temp, len + 1, format, arg);
printf(temp); // replace with any print function you want
va_end(arg);
if (len >= sizeof(loc_buf)) {
free(temp);
}
return len;
}
훌륭한 C++11에서는 다음과 같은 다양한 템플릿을 사용할 수 있습니다.
template <typename... Ts>
void format_string(char *fmt, Ts ... ts) {}
template <typename... Ts>
void debug_print(int dbg_lvl, char *fmt, Ts... ts)
{
format_string(fmt, ts...);
}
매크로도 사용할 수 있습니다.
#define NONE 0x00
#define DBG 0x1F
#define INFO 0x0F
#define ERR 0x07
#define EMR 0x03
#define CRIT 0x01
#define DEBUG_LEVEL ERR
#define WHERESTR "[FILE : %s, FUNC : %s, LINE : %d]: "
#define WHEREARG __FILE__,__func__,__LINE__
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define DEBUG_PRINT(X, _fmt, ...) if((DEBUG_LEVEL & X) == X) \
DEBUG(WHERESTR _fmt, WHEREARG,__VA_ARGS__)
int main()
{
int x=10;
DEBUG_PRINT(DBG, "i am x %d\n", x);
return 0;
}
함수 호출에 인라인어셈블리를 사용할 수 있습니다.(이 코드에서는 인수가 문자라고 가정합니다).
void format_string(char *fmt, ...);
void debug_print(int dbg_level, int numOfArgs, char *fmt, ...)
{
va_list argumentsToPass;
va_start(argumentsToPass, fmt);
char *list = new char[numOfArgs];
for(int n = 0; n < numOfArgs; n++)
list[n] = va_arg(argumentsToPass, char);
va_end(argumentsToPass);
for(int n = numOfArgs - 1; n >= 0; n--)
{
char next;
next = list[n];
__asm push next;
}
__asm push fmt;
__asm call format_string;
fprintf(stdout, fmt);
}
가변 함수는 위험할 수 있습니다.더 안전한 방법이 있습니다.
void func(type* values) {
while(*values) {
x = *values++;
/* do whatever with x */
}
}
func((type[]){val1,val2,val3,val4,0});
로스의 용액이 좀 깨끗해졌어요.모든 arg가 포인터일 경우에만 작동합니다.또한 언어 구현은 다음과 같은 경우 이전 쉼표 삭제를 지원해야 합니다.__VA_ARGS__
비어 있습니다(Visual Studio C++와 GCC 모두 비어 있습니다).
// pass number of arguments version
#define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__}; _actualFunction(args+1,sizeof(args) / sizeof(*args) - 1);}
// NULL terminated array version
#define callVardicMethodSafely(...) {value_t *args[] = {NULL, __VA_ARGS__, NULL}; _actualFunction(args+1);}
예를 들어, 작성한 전형적인 바리에타 함수가 있다고 합시다.변수 변수 앞에 하나 이상의 인수가 필요하기 때문입니다....
사용법에서는 항상 추가 인수를 작성해야 합니다.
아니면 당신은요?
매크로로 바리어드 함수를 랩하는 경우 arg를 선행할 필요가 없습니다.다음 예를 생각해 보겠습니다.
#define LOGI(...)
((void)__android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__))
매번 첫 번째 인수를 지정할 필요가 없기 때문에 이 방법이 훨씬 편리합니다.
이것이 모든 컴파일러에서 기능하는지는 잘 모르겠지만, 지금까지는 기능하고 있습니다.
void inner_func(int &i)
{
va_list vars;
va_start(vars, i);
int j = va_arg(vars);
va_end(vars); // Generally useless, but should be included.
}
void func(int i, ...)
{
inner_func(i);
}
필요에 따라 inner_func()에 ...을 추가할 수 있지만, 필요 없습니다.va_start는 지정된 변수의 주소를 시작점으로 사용하기 때문에 작동합니다.이 경우 func()의 변수를 참조합니다.따라서 이 주소를 사용하여 스택의 다음 변수를 읽습니다.inner_func() 함수는 func()의 스택주소를 읽고 있습니다.따라서 두 함수가 같은 스택세그먼트를 사용하는 경우에만 동작합니다.
va_start 매크로와 va_arg 매크로에 시작점으로 var를 지정하면 일반적으로 동작합니다.따라서 원하는 경우 포인터를 다른 함수에 전달하여 사용할 수 있습니다.자신만의 매크로를 쉽게 만들 수 있습니다.매크로가 실행하는 것은 타입캐스트 메모리 주소뿐입니다.그러나 모든 컴파일러와 호출 규약에 대해 작업하게 하는 것은 성가신 일입니다.따라서 일반적으로 컴파일러와 함께 제공되는 것을 사용하는 것이 더 쉽습니다.
언급URL : https://stackoverflow.com/questions/205529/passing-variable-number-of-arguments-around
'programing' 카테고리의 다른 글
vuex를 사용할 때 typescript 구문에서 mapState 함수를 사용하는 방법 (0) | 2022.05.28 |
---|---|
어레이에서 Array List를 만듭니다. (0) | 2022.05.28 |
Vue - 사용자가 오프라인 상태인지 확인하고 온라인 상태가 되면 div를 표시합니다. (0) | 2022.05.28 |
v-on: 키업이 기동하지 않는 기능 (0) | 2022.05.28 |
vuex 게시 요청에서 상태의 값을 전달하는 방법 (0) | 2022.05.28 |