I have this function:
void print(THashEntry *entry, ...)
{
va_list parameters;
va_start(parameters, entry);
while (true)
{
THashEntry *currentEntry = va_arg(parameters, THashEntry *);
if (!currentEntry)
{
break;
}
printf("%s\n", currentEntry->value);
}
va_end(parameters);
}
I pass adresses of these entries into the function and then I want to access their member "value" and print it.
However when I try to obtain a parameter via va_arg, it returns me not the first, but the second parameter right from the start and when another loop of cycle goes in, it's segmentation fault.
As John Kugelman states in his answer, here are some of the good practices to pass variable number of arguments to printf/sprintf:-
void Error(const char* format, ...)
{
va_list argptr;
va_start(argptr, format);
vfprintf(stderr, format, argptr);
va_end(argptr);
}
I apologize for butting into your design but this might be an alternative to use
struct abc {
int a;
char b[10];
};
void f(int size, abc* a) {
for (int i = 0; i < size; i++) {
abc x = a[i];
}
}
int _tmain(int argc, _TCHAR* argv[])
{
abc *arrAbc = new abc[10];
for (int i = 0; i < 10; i++) {
arrAbc[i].a = 0;
}
f(10, arrAbc);
}
va_arg won't return NULL when you reach the end of argument list. As man va_arg says:
random erros will occur
So to get around it you either need to pass number of arguments to your print function, or end terminator.
To automatically calculate number of arguments at compile time, you can use macro
#define NUMARGS(...) (sizeof((int[]){__VA_ARGS__})/sizeof(int))
See more details in this answer
Seems like there are quite a few answers, but personally I've never found a great way to get around dynamically counting the number of args in a va_list.
That said, there are several ways around it:
Use the NUMARGS(...) macro as noted by qrdl
Pass the number of args into the function like as main does void print(int numArgs, MyEntry *entry, ...)
Use a NULL terminated list
The latter happens to be my personal preference, since it tends to go with my (and it looks like yours too) instinct to how to catch the end of the list. See below:
#import <stdarg.h>
typedef struct MyEntry {
int a;
int b;
} MyEntry;
void print(int numArgs, MyEntry *entry, ...) {
va_list parameters;
va_start(parameters, entry);
MyEntry *m;
for ( m = entry; m != NULL; m = va_arg(parameters, MyEntry *)) {
printf("%d\n", (int)m->a);
}
va_end(parameters);
}
int main(int argc, char *argv[]) {
MyEntry entry = { 10, 20 };
MyEntry entry2 = { 30, 40 };
MyEntry entry3 = { 50, 60 };
MyEntry entry4 = { 70, 80 };
MyEntry entry5 = { 90, 100 };
print(2, &entry, &entry2, &entry3, &entry4, &entry5, NULL);
return 1;
}
Happy coding!
Related
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
typedef struct {
char name[128], code[128];
} info;
info db[3];
info* data=db;
void find (const char *code, int size, ...) {
bool mismatch = true;
va_list arg;
va_start(arg,size);
while (size-- > 0) {
data = va_arg(arg,info*);
printf("%s", data->code);
if (!strcmp(data->code,code))
{
printf("%s [id:%s]\n",data->name,data->code), mismatch = false;
}
}
if (mismatch) printf("No data available!");
return;
}
int main (int argc, char *argv[], char *envp[]) {
const char *spec[] = {
"Physics of Elementary Particles",
"Physics of Hign Energy",
"Low-level Programming"
};
const char *code[] = {
"2396","0812", "0773"
};`enter code here`
for (int count = 0; count < 3; ++count) {
strncpy(db[count].name,spec[count],128);
strncpy(db[count].code,code[count],128);
}
find("0812",3,db[0],db[1],db[2]);
return 0;
}
After running it says "read access violation", although I hope everything is correct, it happens after function "va_arg(arg, info*)". Is it some troubles with stack or decrypting?
The problem is in the function call:
find("0812",3,db[0],db[1],db[2]);
The variadic argument that you're passing in are of type info. However, when you retrieve them with va_arg you're looking for a info *. These don't match up.
You want to pass in the address of each array member.
find("0812",3,&db[0],&db[1],&db[2]);
Also, you need to call va_end at the bottom of find before you return.
I would like to know how I would go about passing any function to a function, as in a generic function pointer that can take any function whatsoever, The goal of this is to make a destructor system, so basically storing the function and calling it with it's arguments also stored later down the line,
Something like:
Defer(SDL_DestroyWindow, Window);
I already handled the arguments, but I don't know how to manage the function pointer part of this, Thank you!
Edit: I added more info ...
typedef struct {
void** args;
} IM_Defer_Resource;
/* Defer & Whatnot */
IM_Stack* IM_Defer_Stack;
void IM_Defer_Init() {
IM_Defer_Stack = IM_Stack_Init();
}
void IM_Defer(/* What to put here? */) {
}
void IM_Defer_All() {
while(IM_Defer_Stack->size) {
IM_Defer_Resource* resource = IM_Stack_Pop(IM_Defer_Stack);
if(!resource) continue;
/* What to do */
}
}
I don't have the actual functions of defer, but I did copy every argument into the stack and can pop them successfully, I don't know how to implement the variadic function calling though
Edit2:
After receiving some input: I think this would be more feasible:
Defer(SDL_DestroyWindow, "SDL_Window*", window);
I am brainstorming how this would be possible, but I would appreciate some input
Edit3:
/* Defer & Whatnot */
typedef struct {
char** types;
void** args;
int count;
} IM_Defer_Resource;
IM_Stack* IM_Defer_Stack;
void IM_Defer_Init() {
IM_Defer_Stack = IM_Stack_Init(IM_Get_Stack_Type(IM_Defer_Resource));
}
void IM_Defer_Internal(void* var, int n, ...) {
char* type;
void* arg;
va_list args;
va_start(args, n);
IM_Defer_Resource resource;
int count = n / 2;
resource->types = calloc(count, sizeof(char*));
resource->args = calloc(count, sizeof(void*));
resource->count = count;
for(count > 0; n -= 1) {
type = va_arg(args, char*);
resource->types[count-1] = type;
arg = va_arg(args, void*);
resource->args[count-1] = arg;
}
IM_Stack_Push(IM_Defer_Stack, &resource);
}
void IM_Defer_All() {
while(IM_Defer_Stack->size) {
IM_Defer_Resource* resource = IM_Stack_Pop(IM_Defer_Stack);
if(!resource) continue;
/* I have a char* and a void* to the resource, Now what? */
free(resource->types);
free(resource->args);
}
}
This is what I came up with, but I am wondering how I can conver that char* into a type...
As I said in comment a big problem is that when declaring a variadic function the undeclared parameters are subject to the default argument promotions. This means that you can find the passed arguments different from that intended by the function, that will eventually lead to exceptions. What you want to do is feasible, but really very complex.
One solution, but limited because requires a lot of coding, could be:
#include <stdarg.h>
#include <stdio.h>
typedef enum { fn1, fn2, fn3, /*....*/} e_fn;
void multi_fun(e_fn fn, ...)
{
va_list ap;
int j;
va_start(ap, fn); /* Requires the last fixed parameter (to get the address) */
switch(fn)
{
case fn1:
{
//suppose prototype for fn1 to be void fn1_fn(int, float, struct mystruct *);
int this_int = va_arg(ap, int);
float this_float = va_arg(ap, float);
struct mystruct *this_struct = va_arg(ap, struct mystruct *);
fn1_fn(this_int, this_float, this_struct);
break;
}
case fn2:
{
...
}
}
va_end(ap);
}
You should take a look at Fake Function Framework (fff) on GitHub. They've done this using macros for caching mock functions. MIT Licensed. However, just like #Frankie_C said, this requires a LOT of code. The header file that defines all of the macros is around 6K LOC. And functions are still limited to 20 arguments.
I just can't figure out how to pass an Argument like in the following scenario:
#include<stdio.h>
void quit(const char*);
int main(void){
const char *exit = "GoodBye";
void (*fptr)(const char*) = quit;
(*fptr)(exit);
return 0;
}
void quit(const char *s){
printf("\n\t%s\n",s);
}
This is how my program should work and it does, but when I make a text menu i just can't figure out how to do it:
#include<stdio.h>
#include<stdlib.h>
int update(void);
int upgrade(void);
int quit(void);
void show(const char *question, const char **options, int (**actions)(void), int length);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])(void) = {update,upgrade,quit};
show(question,options,actions,3);
return 0;
}
int update(void){
printf("\n\tUpdating...\n");
return 1;
}
int upgrade(void){
printf("\n\tUpgrade...\n");
return 1;
}
int quit(void){
printf("\n\tQuit...\n");
return 0;
}
void show(const char *question, const char **options, int (**actions)(void), int length){
int choose = 0, repeat = 1;
int (*act)(void);
do{
printf("\n\t %s \n",question);
for(int i=0;i<length;i++){
printf("%d. %s\n",(i+1),options[i]);
}
printf("\nPlease choose an Option: ");
if((scanf("%d",&choose)) != 1){
printf("Error\n");
}
act = actions[choose-1];
repeat = act();
if(act==0){
repeat = 0;
}
}while(repeat == 1);
}
Here I need to change the quit function (int quit(void); to int quit(char *s){};) like in the First example and call it with an argument like const char *exit = "GoodBye"; ==>> (*fptr)(exit);
I know that at this point my program takes only void as argument, but I done it only to illustrate the problem.
I'm very confused about this.
EDIT:
this int (*actions[3])(void) I think is an Array of Function pointers and all 3 function pointers takes void as argument, but I need to know if i can use one pointer to take an argument or i have to re-code the whole program.
Since you have an array of function pointers, all the functions need to be of the same type. So at the very least each function should take a const char * (not all functions need to use it) and the array type should be changed to match.
If you want something more flexible, you can have the functions accept a single void * so each function can be passed a different parameter which it then casts to the appropriate type. This is how pthreads passes parameters to functions which start a new thread. You will lose some compile-time type checking with this, so be careful if you go this route.
EDIT:
An example of the latter:
#include<stdio.h>
#include<stdlib.h>
int update(void *);
int upgrade(void *);
int quit(void *);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])(void *) = {update,upgrade,quit};
show(question,options,actions,3);
return 0;
}
int update(void *unused){
printf("\n\tUpdating...\n");
return 1;
}
int upgrade(void *unused){
printf("\n\tUpgrade...\n");
return 1;
}
int quit(void *message){
printf("\n\tQuit...%s\n", (char *)message);
return 0;
}
void show(const char *question, const char **options, int (**actions)(void *), int length){
...
if (act == quit) {
repeat = act("GoodBye");
} else {
repeat = act(NULL);
}
...
}
Since you are using a an array of function pointers, you don't know which ones to take which arguments. But have You can avoid re-coding it by making the functions to take "unspecified number of arguments". i.e. Remove the void from as the parameter from function definitions and prototypes from of the function pointers and from the quit() function.
int quit(const char*);
void show(const char *question, const char **options, int (**actions)(), int length);
int main(void){
const char *question = "Choose Menu\n";
const char *options[3] = {"Update", "Upgrade", "Quit"};
int (*actions[3])() = {update,upgrade,quit};
...
}
int quit(const char *msg){
printf("\n\tQuit...%s\n", msg);
return 0;
}
void show(const char *question, const char **options, int (**actions)(), int length){
....
int (*act)();
....
}
This works because C allows a function with no explicit parameters to take "unspecified number of arguments". Otherwise, you need to make all functions have similar signatures.
I have a program which does concatenation.
its like char *testConc(int a,..)
Where a indicates number of arguments are being passed for concatenation.
As legth keeps on changing is there is anything like constructor overloading in C
or any simple syntax which implements the functionality
Yes, there are varadic functions
#include <stdio.h>
#include <stdarg.h>
/* print all non-negative args one at a time;
all args are assumed to be of int type */
void printargs(int arg1, ...)
{
va_list ap;
int i;
va_start(ap, arg1);
for (i = arg1; i >= 0; i = va_arg(ap, int))
printf("%d ", i);
va_end(ap);
putchar('\n');
}
int main(void)
{
printargs(5, 2, 14, 84, 97, 15, 24, 48, -1);
printargs(84, 51, -1);
printargs(-1);
printargs(1, -1);
return 0;
}
C does not have function overloading capabilities. The syntax you have is called a variadic function, which can be used to perform what you asked.
The textConc function would look something like this:
char *textConc(int argc, ...)
{
va_list args;
char *str = NULL;
size_t len = 0;
va_start(args, argc);
while (argc--)
{
/* next string */
const char *temp = va_arg(args, const char *);
size_t size = strlen(temp);
/* make room and copy over */
str = realloc(str, len+size+1);
memcpy(str+len, temp, size+1);
/* new length */
len += size;
}
va_end(args);
return str;
}
int main(int argc, char **argv)
{
char *example = textConc(4, "Hello", "All", "good", "morning");
puts(example);
free(example);
return 0;
}
If you use GCC, we can fake overloading completely, using a little help of macros.
Rename textConc to textConcN and use the following macros:
#define ARGCOUNT(...) (sizeof((const char *[]){__VA_ARGS__})/sizeof(const char *))
#define textConc(...) textConcN(ARGCOUNT(__VA_ARGS__), __VA_ARGS__)
int main(int argc, char **argv)
{
/* notice, no more need for the number of arguments */
char *example = textConc("Hello", "All", "good", "morning");
puts(example);
free(example);
return 0;
}
Functions can't be overloaded in C.
You could rewrite your function as char *testConc(const char *s, ...), where you mark the end of the list with NULL:
testConc("foo", "bar", "baz", "quux", (char *)0);
This makes adding changing the number of actual arguments easier. If you have a C99 compiler, you can even write a wrapping macro that adds the NULL for you:
#define TESTCONC(...) testConc(__VA_ARGS__, (char *)0)
How can i pass (and access) using C, not c++, variable parameters into a function?
void foo(char* mandatory_param, char* optional_param, char* optional_param2...)
thanks
/fmsf
Use stdarg.h
You need to use va_list and then use the macros va_start, va_arg, and va_end.
For more information, see http://www.acm.uiuc.edu/webmonkeys/book/c_guide/2.10.html
It sounds like you are looking for varargs.
#include <stdarg.h>
void foo(const char *fmt, ...)
{
va_list argp;
va_start(argp, fmt);
int i = va_arg(argp, int);
// Do stuff...
va_end(argp);
}
Read about Variable Arguments in C
#include <stdarg.h>
void do_sth (int foo, ...)
{
int baz = 7; /* "baz" argument */
const char *xyz = "xyz"; /* "xyz" argument */
/* Parse named parameters */
va_list ap;
va_start (ap, foo);
for (;;) {
const char *key = va_arg (ap, char *);
if (key == NULL) {
/* Terminator */
break;
} else if (strcmp (key, "baz") == 0) {
baz = va_arg (ap, int);
} else if (strcmp (key, "xyz") == 0) {
xyz = va_arg (ap, char *);
} else {
/* Handle error */
}
}
va_end (ap);
/* do something useful */
}
do_sth (1, NULL); // no named parameters
do_sth (2, "baz", 12, NULL); // baz = 12
do_sth (3, "xyz", "foobaz", NULL); // xyz = "foobaz"
do_sth (4, "baz", 12, "xyz", "foobaz", NULL); // baz = 12, xyz = "foobaz"
Variadic functions and arguments assignment in C/C++
In a language that does not support optional parameters directly, there are a few ways to achieve a similar effect. I will list them in order from the least versatile to the most:
Create multiple overloads of the same function. As I recall, you cannot do this in C.
Use variadic functions. Just Google this: http://www.google.com/search?q=variadic+function+c
I recommend this: Create a "params" or "args" class (or struct in C), like this:
)
// untested C code
struct FooArgs {
char * mandatory_param;
char * optional_param;
char * optional_param2;
// add other params here;
};
and then make your method call take in a single argument:
// untested
void foo(struct fooArgs * args)
This way, as needs change, you can add parameters to fooArgs without breaking anything.
I have a solution that does not use VA_LIST in pure C. However, it works at 32bits only. Here, what happens is that each parameter of the call stack occupies as many bytes according to its type. It is possible to create a structure with a size larger than 4 or 8 bytes, so just align all the parameters in this structure.
int printf(void*,...);
typedef struct{
char p[1024];
}P_CALL;
int soma(int a,int b){
return a+b;
}
void main(){
P_CALL
call;
char
*pcall=(void*)&call;
int
(*f)()=soma,
res;
*(int*)pcall=1;
pcall+=sizeof(void*);
*(int*)pcall=2;
pcall+=sizeof(void*);
res=f(call);
printf("%d\n",res);//3
}