stdarg и что здесь вообще происходит?
Написал простейший код с использованием varidatic functions
#include <stdio.h>
#include <stdarg.h>
typedef void (*callback_ft)();
void OnPlayerJoin(int, char*);
void OnPlayerDisconnect(int, char*, int);
void call(callback_ft callback, ...) {
va_list args;
va_start(args, callback);
callback(args);
va_end(args);
}
int main(int argc, char* argv[]) {
call(OnPlayerJoin, "Mike");
call(OnPlayerJoin, "Bob", "Hello"); // неправильный вызов
call(OnPlayerDisconnect, "John", 176);
call(OnPlayerDisconnect, "John"); // неправильный вызов
}
void OnPlayerJoin(int n, char* name) { printf("Hi %s!\n", name); }
void OnPlayerDisconnect(int n, char* name, int time) { printf("%s disconnected! Played for %imin\n", name, time); }
Код работает, запускается и выводит:
Но у меня возникло 3 вопроса:
- Почему при указании сигнатуры функции с пустыми параметрами, в вызываемые аргументы передаются правильно, даже с учётом того, что первый опорный параметр n явно не передаётся?
- Почему при неправильном вызове код продолжает более-менее адекватно работать не вываливаясь сразу в segfault?
- Насколько такой код переносим и насколько его опасно применять в реальных проектах?
Я действительно не понимаю как это работает и почему это вообще работает...
[Visual Studio 2022 | Стандартные настройки проекта, кроме флагов /TC и /std:c17]
Ответы (1 шт):
Автор решения: AlexGlebe
→ Ссылка
Тип
typedef void (*callback_ft)();означает указатель на функцию с аргументом типаvoidилиint. Но никак неva_list
Неправильное использование функции приводит к неопределённому поведению. UB... UB
Никак не переносим.
Переносимым будет если вы передадите функциям указатель на список аргументов. И не надеяться на удачу.
#include <stdio.h>
#include <stdarg.h>
typedef void (*callback_ft)(va_list*);
// int n , char * name
void OnPlayerJoin(va_list*);
// int n , char * name , int time
void OnPlayerDisconnect(va_list*);
void call(callback_ft callback, ...) {
va_list args;
va_start(args, callback);
callback(&args);
va_end(args);
}
int main(int argc, char* argv[]) {
call(OnPlayerJoin, (int)0,(char*)"Mike");
call(OnPlayerJoin, (int)1,(char*)"Bob");
call(OnPlayerDisconnect,(int)0,(char*)"John", (int)176);
call(OnPlayerDisconnect, (int)1,(char*)"John",(int)5);
}
void OnPlayerJoin(va_list*const l) {
int n = va_arg(*l, int);
char* name = va_arg(*l, char*);
printf("Hi %s!\n", name);
}
void OnPlayerDisconnect(va_list*const l) {
int n = va_arg(*l, int);
char* name = va_arg(*l, char*);
int time = va_arg(*l, int);
printf("%s disconnected! Played for %imin\n",
name, time);
}
