Using the "..." argument in functions in C with no headers - c

I'm creating my own kind of C library with my own kind of functions and also to help be better understand C and not just depend on GNU C Library for everything.
So far I got a bit of functions running but I wan't to tweak my printo function a little bit to support unlimited arguments (Restricted to chars only but your answer may also support passing in integer arguments). Here is the printo code:
#include "../GV.h"
#include "OtherUtils.h"
int print(char *WRITEOUT1){
char *WRITEOUT=&WRITEOUT1[0];
int AMOUNT=GetCharSize(WRITEOUT1);
register int SYSCALLNO asm("rax")=SYSWRITE;
register int FD asm("rdi")=STANDARDFD;
register char *BUF asm("rsi")=WRITEOUT;
register int BYTES asm("rdx")=AMOUNT;
asm("syscall");
return 0;
}
GetCharSize function code if anyone needs it:
#include "../GV.h"
int GetCharSize(char *arg){
for(i=0;arg[i]!='\0';i++){
}
return i;
}
GV.h has variables defined like int i;
Before I asked this question I looked into C pre-processors like __VA_ARGS__ but I somewhat couldn't wrap my head around it.

The ... notation is a part of the syntax of the C language. It is used in defining the argument list of a function as the last argument and means "followed by zero or more arguments of any type". E.g.
int printf (char *format, ...);
A function defined in this way can now be called with all the mandatory arguments, plus any number of additional arguments, like printf.
A function defined is this way must have a means of knowing how many arguments there are, and what the type of each argument is. printf knows this from the format specification string, the only required argument of printf.
Assuming an Intel system that uses a stack to pass arguments, and where arguments are pushed right-to-left (last argument pushed first), so the first optional argument will be directly after the format specification string on the stack, printf now proceeds as follows: take the address of the format specfication string and increment that address with the size of a char *. This is the start of the optional arguments. Now look at the format specifier string to know the type of the next argument; get that type of argument from the stack, increment it with the size of that argument to get the next address. Do this until there are no more format specifiers.

Related

Can you have in C variable length arguments functions with cases when you don't want to pass any variable?

I want to create a function in C with variable length arguments in which I may not want to pass any variable at some point. I such a thing possible in C? I would like some code snippets if possible. Also, I have to mention that the function will have passed only char* variables when there are passed some variables.
A function with variable arguments must have at least one names argument in order to read the others.
For your particular case, since you want to pass a list of char * arguments you can use NULL to denote the end of the argument list. So in the case where there is nothing to pass, you just pass a singe NULL argument.
This is not supported by standard C.
For a function parameter type list terminated with an ellipsis, there must be at least one named parameter.
For a function defined with an identifier list, the number of arguments in the call must match the number of parameters in the definition; varying numbers of arguments are not supported.
If you will call a function with a varying number of char * arguments, and that number may be zero, you could declare the function with a dummy first argument that is always passed but never used, as with:
void foo(int dummy,...);
Note that passing no arguments is a troublesome design. Normally, routines that accept varying numbers of arguments infer the number of arguments from one or more arguments. For example, the first argument might contain the number of remaining arguments, or it might be a format string (as with printf) from which the number and types of remaining arguments can be deduced. If you want a function to accept zero arguments in some situations, it has to have a way of knowing whether it was called with zero arguments or more. That would require information in some global state, which is typically a bad design.
no you cant
you need at least one known argument
void foo(int dummy, ...)
{
va_list ap;
C does not provide any mechanism to allow a called function to determine how many arguments were provided. The mechanism must be part of the calling interface.
For example, printf relies on the % format specifications, while execv requires the caller to place a null pointer as the last argument.
A varargs function can be called with no variable arguments, but the caller must not attempt to access any variable argument in that case. For example, the mode argument to the Posix open() function is only consulted in the case that a new file is created, so it need not be supplied if the flags argument doesn't contain the O_CREAT flag (or some other extension flag, such as O_TMPFILE in Linux, which requests file creation).
The variable-length part of the prototype must follow at least one fixed argument. So it is not possible fir a varargs function to be called with no arguments at all.
Can you have in C variable length arguments functions with cases when you don't want to pass any variable?
Yes. In modern C, Code cannot define a ... function with no arguments, yet you can call such a function with no arguments by declaring the a function without function signature. In that way the function can be called with zero arguments.
The function still needs some way to understand the count of arguments. This is often done with the first argument as a count (or format) or a final argument as a sentinel.
Given "will have passed only char*"...
int foo_count(int counter, ...);
// zero usage example
foo_count(0);
int foo_sentinel(char *s);
// zero usage example
foo_sentinel((char*) NULL);
To do so with passing no arguments, the count needs to be conveyed in some other fashion, perhaps with a global variable - although this is not recommended. (Better to simply pass the count.)
Declare function:
int foo_count;
int foo(); // no prototype
Call function
foo_count = 0; foo()
foo_count = 1; foo("one")
foo_count = 2; foo("one", "two")
Define the function
int foo(char *s1, ...) {
if (foo_count > 0) {
va_list ap;
va_start(ap, s1);
puts(s1);
for (int i=1; i < foo_count; i++) {
puts(va_arg(ap, char *));
}
va_end(ap);
}
}

Variable length arguments in C

Why do I have to take an int type variable in c var_args function? Like printf is a built-in function that does not require the length of arguments to be declared before entering various variables...
The C standard does not require a function with a variable parameter list to have any particular argument type.
However, it is up to the function to make appropriate invocations to va_arg. To do that, the function has to have some way of knowing what arguments have been passed. You may implement that requirement in any way you desire, including:
Use a format string that contains conversion specifiers that indicate the argument types, as printf does.
Pass any description of the numbers and types of each argument. Encode them all in one array, pass several arguments describing the rest, describe one argument, then have that argument, then describe the next argument, then have that argument, and so on.
Deduce the arguments from the operation the function is requested to perform. For example, an open call might take flags that indicate whether it should create a file or just open an existing one. If it is to create a file, then it could take an additional parameter indicating the permissions to be set on the file, whereas, if it is merely opening an existing file, it would not take that parameter.
The answer has to do with compiler calling conventions. Here's a slightly simplified explanation:
Basically, when the compiler encounters a function call with N arguments, it generates code to push N arguments on the stack.
When the compiler compiles a function which takes N arguments, it generates code to pops N arguments off the stack.
There is no "secret" information telling the function how many arguments were pushed. For ordinary functions, the number and type of arguments agree only because the function prototype in the calling code agrees with the function definition.
For variadic functions, it's not possible to rely on the function definition. The ... literally means "we don't know what arguments will be pushed. So there needs to be an alternate source for the argument specification. A simple way to do it is just ensure the first argument is the count of fixed-size arguments to follow.
printf and family use a different method. The format string defines what type and how many arguments it will use.
C does not allow a variable argument function to optionally take zero parameters. That is, there must be a named parameter before the ....
For printf, the named parameter is the format string. When parsing the format string, the type of the next argument can be deduced, and the va_arg macro can be properly invoked.
If all the arguments are of the same type, you can use the named parameter to indicate the number of arguments being passed in. For example, if you are passing in a number of strings:
void foo_strings (int n, ...) {
va_list ap;
va_start(ap, n);
while (n--) {
const char *s = va_arg(ap, const char *);
foo(s);
}
va_end(ap);
}
However, you could have just as easily used a NULL to indicate there are no more strings. Then, the first argument could be used for something else, such as pointing to a function.
void foo_string (void (*foo)(const char *), ...) {
va_list ap;
va_start(ap, n);
const char *s = va_arg(ap, const char *);
while (s != NULL) {
foo(s);
s = va_arg(ap, const char *);
}
va_end(ap);
}

Unspecified number of parameters in C functions - void foo()

I read here that in C void foo() means a function foo taking an unspecified number of arguments of unspecified type.
Can anyone give me or point me to an example where a C function takes an unspecified number of arguments? What can this be applied to in C? I couldn't find anything on the web.
That's an old-style function declaration.
This declaration:
void foo();
declares that foo is a function returning void that takes an unspecified but fixed number and type(s) of arguments. It doesn't mean that calls with arbitrary arguments are valid; it means that the compiler can't diagnose incorrect calls with the wrong number or type of arguments.
Somewhere, perhaps in another translation unit (source file), there has to be a definition of the function, perhaps:
void foo(x, y)
long x;
double *y;
{
/* ... */
}
This means that any call to foo that doesn't pass two arguments of type long and double* is invalid, and has undefined behavior.
Prior to the 1989 ANSI C standard, these were the only kind of function declaration and definition available in the language, and the burden of writing correct function calls was entirely on the programmer. ANSI C added prototypes, function declarations that specify the types of a function's parameters, which allow compile-time checking of function calls. (This feature was borrowed from early C++.) The modern equivalent of the above would be:
void foo(long x, double *y);
/* ... */
void foo(long x, double *y) {
/* ... */
}
Old-style (non-prototype) declarations and definitions are still legal, but they're officially obsolescent, which means that, in principle, they could be removed from a future version of the language -- though since they're still around in the 2011 standard I don't know that that will ever actually happen.
There is no good reason to use old-style function declarations and definitions in modern C code. (I've seen arguments for using them in some corner cases, but I find them unconvincing.)
C also supports variadic functions like printf, which do take an arbitrary number of arguments, but that's a distinct feature. A variadic function must be declared with a prototype, which includes a trailing , .... (Calling a variadic function with no visible prototype isn't illegal, but it has undefined behavior.) The function itself uses macros defined in <stdarg.h> to process its parameters. As with old-style function declarations, there is no compile-time checking for arguments corresponding to the , ... (though some compilers may check some calls; for example gcc warns if the arguments in a printf call are inconsistent with the format string).
This literally means that you are not telling the compiler what arguments the function takes, this means that it will not protect you from calling it with any arbitrary set of arguments. You would need to say in the definition precisely what arguments are actually taken for the function to be implemented however.
You could for example use this if you were generating a header file to describe a foreign function in external code, however you did not know what the function's signature actually was, it would still then be callable using your header but if you provide the wrong arguments in the call results are undefined.
The declaration void foo(); is not necessarily the same thing as a function that takes a variable number of arguments.
All that it is is a function declaration that indicates nothing about the number of arguments the function takes (actually, this is not exactly true, see below about argument promotions). The declaration isn't a function prototype, which provides information about the number and types of the parameters (using an ellipsis to indicate variable length parameters).
The function definition (where the body of the function is provided) might take a fixed number of arguments, and might even have a prototype.
When such a function declaration is used, it is up to the programmer making a call to foo() to get the arguments that foo() expects (and their types) correct - the compiler has no information about the argument list foo() requires. It also restricts the type of parameters that the function definition can use because when the function is called without a prototype, therefore the default argument promotions will be applied to the arguments at the function call. So a function that's declared without a prototype can only expected to get promoted arguments.
See the following C99 standard sections for some details:
6.7.5.3/14 "Function declarators (including prototypes)
...
The empty list in a function declarator that is not part of a
definition of that function specifies that no information about the
number or types of the parameters is supplied.
...
6.5.2.2 Function calls
...
If the expression that denotes the called function has a type that
does not include a prototype, the integer promotions are performed on
each argument, and arguments that have type float are promoted to
double. These are called the default argument promotions. If the
number of arguments does not equal the number of parameters, the
behavior is undefined. If the function is defined with a type that
includes a prototype, and either the prototype ends with an ellipsis
(, ...) or the types of the arguments after promotion are not
compatible with the types of the parameters, the behavior is
undefined. If the function is defined with a type that does not
include a prototype, and the types of the arguments after promotion
are not compatible with those of the parameters after promotion, the
behavior is undefined, except for the following cases:
one promoted type is a signed integer type, the other promoted type is the corresponding unsigned integer type, and the value is
representable in both types;
both types are pointers to qualified or unqualified versions of a character type or void.
The C function calling standard allows for a function to be called with zero or more arguments and the number of arguments may or may not match the function interface.
The way this works is that it is up to the caller to adjust the stack after the called function returns rather than the called function adjusting the stack unlike other standards such as Pascal which require the called function to manage the stack adjustment properly.
Because the caller knows what arguments and their types have been pushed onto the stack before the called function is called and the called function does not, it is up to the caller to clear the pushed arguments from the stack after the called function returns.
With updated C standards, the function call interface description has become more complex in order to allow the compiler to detect and report interface problems that the original K&R C standard allowed to go undetected by the compiler.
The standard now is that you specify variable argument lists using elipsis notation of three periods or dots after the last known and specified argument in the called functions interface specification or declaration.
So you would see something like the following for some of the Standard C Library I/O functions:
int sprintf (char *buffer, char *format, ...);
This indicates that the function sprintf requires that the first argument be a char pointer to a buffer, the second argument be a char pointer to a format string, and there may be other additional arguments. In this case any additional arguments would be what are needed to be inserted for the print format specifiers in the format string. If the format string is just a text string with no format specifies (something like %d for an integer for instance) then there would be no other arguments.
The newer C Standards specify a set of functions/macros for the use with variable argument lists, the varg functions. With these functions/macros the called function can step through the variable part of an argument list and process the arguments. These functions look something like the following:
int jFunc (int jj, char *form, ...)
{
va_list myArgs;
int argOne;
va_start (myArgs, form);
argOne = va_arg (myArgs, int);
va_end (myArgs);
return 0;
}
The problem that we have with variable argument lists is that C does not have a way of communicating the variable argument or even how many arguments. So the designer of the function has to provide a mechanism. In the case of the C Standard Library I/O functions this is done with the format that indicates the number of arguments following the format string by specifying format specifiers for each argument. And since there is nothing that does a consistency check, you can end up with a format string that specifies more or less than the actual arguments resulting in either garbage output or less output than expected.
Since modern C compilers have some degree of backwards compatibility for old C source code, that means that you can use some of the older constructs and the compiler will allow it though hopefully with a warning.
The new function interface specifications are designed to reduce the chances of using a function incorrectly. So the new standards recommend that you use the function interface declaration so that the compiler can help you by detecting interface problems and incorrect variable usage in the function call.
However if you want to be a risk taker you do not have to use this safety net so if you like you can just define a function with an empty argument list and wing it.
You might also find an answer I put into this question about currying in C that uses variable argument lists along with a way to determine how many arguments are provided.
As mentioned in many other answers, a function taking an unspecified number of arguments of unspecified type just means it's caller doesn't know about its definition. It's completely different from variadic functions where you must define with ... and then use va_list in stdarg.h to obtain the arguments
It's actually common in the past and there are many standard functions using that feature, for example open()/openat()/_open() with an optional last parameter
fd = open(filename, O_RDONLY);
fd = open(filename, O_CREAT | O_WRONLY, 0777);
See open() function parameters
main() is also a function that can receive varying number of arguments
int main();
int main(int argc, char **argv);
int main(int argc, char **argv, char **envp);
int main(int argc, char **argv, char **envp, char **apple);
In fact the Windows x64 calling convention is designed to support such unspecified number of arguments so it's a bit unfortunate for most modern usecases

Why do I have to specify data type each time in C to printf() and scanf()?

As you can see from the code snippet below, I have declared one char variable and one int variable. When the code gets compiled, it must identify the data types of variables str and i.
Why do I need to tell again during scanning my variable that it's a string or integer variable by specifying %s or %d to scanf? Isn't the compiler mature enough to identify that when I declared my variables?
#include <stdio.h>
int main ()
{
char str [80];
int i;
printf ("Enter your family name: ");
scanf ("%s",str);
printf ("Enter your age: ");
scanf ("%d",&i);
return 0;
}
Because there's no portable way for a variable argument functions like scanf and printf to know the types of the variable arguments, not even how many arguments are passed.
See C FAQ: How can I discover how many arguments a function was actually called with?
This is the reason there must be at least one fixed argument to determine the number, and maybe the types, of the variable arguments. And this argument (the standard calls it parmN, see C11(ISO/IEC 9899:201x) ยง7.16 Variable arguments ) plays this special role, and will be passed to the macro va_start. In another word, you can't have a function with a prototype like this in standard C:
void foo(...);
The reason why the compiler can not provide the necessary information is simply, because the compiler is not involved here. The prototype of the functions doesn't specify the types, because these functions have variable types. So the actual data types are not determined at compile time, but at runtime.
The function then takes one argument from the stack, after the other. These values don't have any type information associated with it, so the only way, the function knows how to interpret the data is, by using the caller provided information, which is the format string.
The functions themselves don't know which data types are passed in, nor do they know the number of arguments passed, so there is no way that printf can decide this on it's own.
In C++ you can use operator overloading, but this is an entire different mechanism. Because here the compiler chooses the appropriate function based on the datatypes and available overloaded function.
To illustrate this, printf, when compiled looks like this:
push value1
...
push valueN
push format_string
call _printf
And the prototype of printf is this:
int printf ( const char * format, ... );
So there is no type information carried over, except what is provided in the format string.
printf is not an intrinsic function. It's not part of the C language per se. All the compiler does is generate code to call printf, passing whatever parameters. Now, because C does not provide reflection as a mechanism to figure out type information at run time, the programmer has to explicitly provide the needed info.
Compiler may be smart, but functions printf or scanf are stupid - they do not know what is the type of the parameter do you pass for every call. This is why you need to pass %s or %d every time.
The first parameter is a format string. If you're printing a decimal number, it may look like:
"%d" (decimal number)
"%5d" (decimal number padded to width 5 with spaces)
"%05d" (decimal number padded to width 5 with zeros)
"%+d" (decimal number, always with a sign)
"Value: %d\n" (some content before/after the number)
etc, see for example Format placeholders on Wikipedia to have an idea what format strings can contain.
Also there can be more than one parameter here:
"%s - %d" (a string, then some content, then a number)
Isn't the compiler matured enough to identify that when I declared my
variable?
No.
You're using a language specified decades ago. Don't expect modern design aesthetics from C, because it's not a modern language. Modern languages will tend to trade a small amount of efficiency in compilation, interpretation or execution for an improvement in usability or clarity. C hails from a time when computer processing time was expensive and in highly limited supply, and its design reflects this.
It's also why C and C++ remain the languages of choice when you really, really care about being fast, efficient or close to the metal.
scanf as prototype int scanf ( const char * format, ... ); says stores given data according to the parameter format into the locations pointed by the additional arguments.
It is not related with compiler, it is all about syntax defined for scanf.Parameter format is required to let scanf know about the size to reserve for data to be entered.
GCC (and possibly other C compilers) keep track of argument types, at least in some situations. But the language is not designed that way.
The printf function is an ordinary function which accepts variable arguments. Variable arguments require some kind of run-time-type identification scheme, but in the C language, values do not carry any run time type information. (Of course, C programmers can create run-time-typing schemes using structures or bit manipulation tricks, but these are not integrated into the language.)
When we develop a function like this:
void foo(int a, int b, ...);
we can pass "any" number of additional arguments after the second one, and it is up to us to determine how many there are and what are their types using some sort of protocol which is outside of the function passing mechanism.
For instance if we call this function like this:
foo(1, 2, 3.0);
foo(1, 2, "abc");
there is no way that the callee can distinguish the cases. There are just some bits in a parameter passing area, and we have no idea whether they represent a pointer to character data or a floating point number.
The possibilities for communicating this type of information are numerous. For example in POSIX, the exec family of functions use variable arguments which have all the same type, char *, and a null pointer is used to indicate the end of the list:
#include <stdarg.h>
void my_exec(char *progname, ...)
{
va_list variable_args;
va_start (variable_args, progname);
for (;;) {
char *arg = va_arg(variable_args, char *);
if (arg == 0)
break;
/* process arg */
}
va_end(variable_args);
/*...*/
}
If the caller forgets to pass a null pointer terminator, the behavior will be undefined because the function will keep invoking va_arg after it has consumed all of the arguments. Our my_exec function has to be called like this:
my_exec("foo", "bar", "xyzzy", (char *) 0);
The cast on the 0 is required because there is no context for it to be interpreted as a null pointer constant: the compiler has no idea that the intended type for that argument is a pointer type. Furthermore (void *) 0 isn't correct because it will simply be passed as the void * type and not char *, though the two are almost certainly compatible at the binary level so it will work in practice. A common mistake with that type of exec function is this:
my_exec("foo", "bar", "xyzzy", NULL);
where the compiler's NULL happens to be defined as 0 without any (void *) cast.
Another possible scheme is to require the caller to pass down a number which indicates how many arguments there are. Of course, that number could be incorrect.
In the case of printf, the format string describes the argument list. The function parses it and extracts the arguments accordingly.
As mentioned at the outset, some compilers, notably the GNU C Compiler, can parse format strings at compile time and perform static type checking against the number and types of arguments.
However, note that a format string can be other than a literal, and may be computed at run
time, which is impervious to such type checking schemes. Fictitious example:
char *fmt_string = message_lookup(current_language, message_code);
/* no type checking from gcc in this case: fmt_string could have
four conversion specifiers, or ones not matching the types of
arg1, arg2, arg3, without generating any diagnostic. */
snprintf(buffer, sizeof buffer, fmt_string, arg1, arg2, arg3);
It is because this is the only way to tell the functions (like printf scanf) that which type of value you are passing. for example-
int main()
{
int i=22;
printf("%c",i);
return 0;
}
this code will print character not integer 22. because you have told the printf function to treat the variable as char.
printf and scanf are I/O functions that are designed and defined in a way to receive a control string and a list of arguments.
The functions does not know the type of parameter passed to it , and Compiler also cant pass this information to it.
Because in the printf you're not specifying data type, you're specifying data format. This is an important distinction in any language, and it's doubly important in C.
When you scan in a string with with %s, you're not saying "parse a string input for my string variable." You can't say that in C because C doesn't have a string type. The closest thing C has to a string variable is a fixed-size character array that happens to contain a characters representing a string, with the end of string indicated by a null character. So what you're really saying is "here's an array to hold the string, I promise it's big enough for the string input I want you to parse."
Primitive? Of course. C was invented over 40 years ago, when a typical machine had at most 64K of RAM. In such an environment, conserving RAM had a higher priority than sophisticated string manipulation.
Still, the %s scanner persists in more advanced programming environments, where there are string data types. Because it's about scanning, not typing.

Pointer to void as an argument in a function with no prototype for variable number of arguments

Say I have a function that should accept any number of parameters, so what im coing here is declaring no prototype, and letting the function to be created when it is called in the code. I am using a pointer to void to receive the random number of parametersparameters, however, when doing this, the reference to the memory addres of the first parameter is the only thing that is passed, so for it to work, i would have to declare variables in the same order that i am going to call them in the code:
unsigned char result=0;
unsigned char a=1;
unsigned char b=2;
unsigned char c=3;
char main (void)
{
for (;;)
{
result = function (&a, &b, &c);
result = function (&c, &b, &a);
}
}
function (void *vPointer)
{
return (1);
}
Also I am declaring function without a type since it would not match the call (where it is implicitly declared also).
The result here is a reference to the first parameter sent in the function, so if i point to the next addres in the first function call, it would work, but in the second call, it gets the reference to c, and whatever memory is ahead of where it is placed.
Anyone know a way of sorting the parameters references the correct way? or an effective way to receive an unknown number of parameters in a function?
NOTE: (...) SHALL NOT be used.
All C functions should have prototypes. They're not actually mandatory, but there's no good reason not to use them (unless you're stuck with a pre-ANSI compiler that doesn't support them). (But see the bottom of this answer.)
If you want a function that takes a variable number of arguments, that prototype should end with , ..., and the function itself should use the <stdarg.h> mechanism to process its arguments. (This requires at least one argument with a defined type; that argument is used as an anchor for the following arguments.) It's documented here and elsewhere.
As I was typing this, you updated your question with "NOTE: No libraries (such as (...) )should be used". <stdarg.h> is one of the handful headers that's required for all conforming C implementations, including freestanding (embedded) ones -- because it doesn't define any functions, just types and macros. Your C implementation should support it. If it doesn't, then it's not a conforming C implementation, and you'll need to tell us exactly what compiler you're using and/or read its documentation to find out how it handles variadic functions, or an equivalent.
If you really can't use , ... and <stdarg.h>, (or perhaps the older <varargs.h>), then you can define your function with a fixed number of arguments, enough for all uses, then have callers pass extra null pointers.
EDIT:
This is an update based on new information in comments and chat.
The OP has a homework assignment to implement printf for some TI microcontroller, for some reason not using either the , ... notation or <stdarg.h>. The compiler in question apparently implements C89/C90, so it does support both features; this is an arbitrary restriction.
This information should have been in the question, which is why I'm downvoting it until the OP updates it.
There is no portable way to achieve this -- which is exactly why , ... is part of the standard language, and <stdarg.h> is part of the standard library.
Probably the best approach would be to write a program that uses , ... and <stdarg.h>, then invoke the compiler so it shows just the output of the preprocessor (resolving the various va_* macros and the va_list type), and then imitate that. And you'd have to assume, or verify using the compiler documentation, that the calling convention for variadic and non-variadic functions is compatible. In other words, find out what this particular implementation does, and reinvent a similar wheel.
(I hope that the point of the homework assignment is to demonstrate how much better the standard techniques are.)
UPDATE 2:
I wrote above that all C functions should have prototypes. This may actually be a rare exception to this rule. At least one of these calls:
printf("Hello\n");
printf("x = %d\n", 42);
must produce a diagnostic from a conforming compiler unless either printf is declared with , ... (which is forbidden by the homework assignment), or there is no visible prototype for printf. If there's no prototype, then at least one of the calls will have undefined behavior (behavior that's not defined by the C standard, though it may be defined by a particular compiler).
In effect, to meet the homework requirements, you'll have to pretend that you're using a pre-ANSI C compiler.
the only "clean" way to use functions with variable arguments is to use variadic functions:
#include <stdarg.h>
void myfun(int foo, ...) {
va_list ap;
va_start(foo, ap);
// ...
va_end(ap);
}
you will need to make sure that you know which arguments you actually expect (usually you either use your first argument to indicate how many (and which) arguments to expect (examples are an int that says "now come arguments", or a format-string like "%d %s:%s", that says now come an int and two char*), or you use a a final terminating argument (e.g. read arguments until you encounter NULL).
You could use an array of variable length:
unsigned char result=0;
unsigned char a=1;
unsigned char b=2;
unsigned char c=3;
function (int len, void *vPointer);
int main (void)
{
for (;;)
{
unsigned char args[3];
args[0] = a;
args[1] = b;
args[2] = c;
result = function (3, args);
args[0] = c;
args[1] = b;
args[2] = a;
result = function (3, args);
}
return 0;
}
function (int len, void *vPointer)
{
return (1);
}
But I recommend you use the standard way instead, i.e. variadic functions.
//jk
You can use a structure:-
typedef struct _Params {
int m_a;
int m_b;
int m_c;
} Params;
Then your parameters can't get mixed up. Just as more letters up to the max you need.

Resources