Is there a way to declare a C variadic function and call it from Fortran?
I need to call this function to compute some dot products between vectors labeled with a string.
My idea was to declare something like the following, where the variable list of arguments contains string literals. If the variable list of arguments is empty, then I would do a lookup among the standard labels and perform the calculation. If the user specified two labels I would retrieve those two vectors and get their dot product:
extern "C" void compute_dot_product(double * dot_product, ...)
{
va_list args;
va_start(args, NULL);
char * label1 = va_arg(args, char *);
if (!label1)
{
// Do standard label lookup and compute dot product
}
else
{
// Compute dot product between the vectors with the specified labels
char * label2 = va_arg(args, char *);
}
va_end(args);
}
the only problem is that I can compile my C library and link it to a Fortran executable, but I get a runtime error when I try to access the variable list of arguments.
Any idea if what I am trying to do is possible?
A possible solution would then be to split into two functions: one that does the standard label lookup (0 argument case), the other that handles the non-standard label lookup (2 argument case). I would rather avoid this solution though.
It is not possible to call a variadic function in a standard conforming (i.e. portable) way.
You could make the definition of the C function take two parameters only (so it is no longer variadic - existing references to the function would need to be modified), with the second parameter in the C function a pointer, either NULL to indicate that there are no additional things being passed, or pointing at an array of pointers (perhaps NULL terminated) or whatever, with any additional things. In F201X an interface body for this sort of function might be able to use the OPTIONAL attribute for the second argument.
Related
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);
}
}
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);
}
Is it possible to make declaration of variadic function so that it doesn't end with "..."?
Today I learned more about exec from unistd.h but through the day I've seen three (two actually) different declaration of execl:
1) int execl ( const char * path, const char * arg0, ..., (char*)NULL ); was shown to us in school and I imagined I would have to end the function call with a NULL value
2) int execl(const char *path, const char *arg, ... /* (char *) NULL */); is what I've found in the exec(3) man page. That would probably mean I still have to end it with a NULL value, but it is not enforced.
3) int execl(const char *path, const char *arg, ...); is what I found here. This one would probably normally put me to rest with the first one being a simplification for students, the second was a varning and this is the real thing (even though I would probably have normally higher regard for both options one and two.)
But then I found on the same site this declaration:
int execle(const char *path, const char *arg, ..., char * const envp[]);
Same question applies, I was unable to create variadic function not ending in ... with gcc telling me that it's expecting ')' before ',' token pointing to the comma after the three dots.
So finally, is it possible to make variadic functions ending with a NULL characters (execl) and if not, is it possible to make it end with predefined variable (execle)?
I tried to compile with gcc 6.3.1, I also tried --std=c11.
Is it possible to make declaration of variadic function so that it doesn't end with "..."?
Is it possible is a slippery question, but consider these facts:
the standard says that "If a function that accepts a variable number of arguments is defined without a parameter type list that ends with the ellipsis notation, the behavior is undefined" (C2011, 6.9.1/8)
Perhaps that answers the question already, but if you choose to mince words and focus on function declarations that are not definitions, then
a function definition is also a declaration
the C language standard requires all declarations of the same function to be "compatible" (else program behavior is undefined) (C2011 6.7/4)
two function declarations with mismatched parameter lists are not compatible (C2011, 6.2.7/3)
Thus, if you declare a variadic function that in fact is also defined, and that function's parameter list does not end with ..., then the program's behavior is undefined.
The documentation you've been reading for execle() and execl() is written to express and discuss those functions' expectations, but to the extent that it seems to present variadic function declarations in which the last element of the parameter list is not ..., those are not actually valid C function declarations.
So finally, is it possible to make variadic functions ending with a NULL characters (execl) and if not, is it possible to make it end with predefined variable (execle)?
It is not possible to describe such calling conventions via conforming C declarations. Variadic functions can have such expectations, and can enforce them at runtime, but they can be enforced at compile time only by a compiler that relies on special knowledge of the functions involved, or on C language extensions that allow such constraints to be described.
The declaration of a variadic function can only specify the required arguments, and the compiler can enforce their types. The variable-length part never has any type checking done. And the variable-length part is always at the end. The declaration for execle() is not meant as an actual C declaration, but just to describe to the programmer how he should construct the arguments.
It's not possible to enforce that the last argument to execl() is NULL. Variadic functions don't know how many arguments were supplied, they determine it from the values of the arguments. printf() assumes that it has enough arguments to fill in all the operators in the format string, and execl() iterates through the arguments until it finds NULL (execle() is similar, but it reads one additional argument to get envp). If you don't end with NULL, it will just keep going, reading garbage and causing undefined behavior.
The declaration you see is the one in the man pages of execl. The declaration for execle in glib is the following: int execle (const char *path, const char *arg, ...). The implementation assumes the last argument is a char**, and uses it for envp. I don't think you can enforce such a rule in C.
Am trying to convert a little bit of C test code into a PostgreSQL v1 module
Code originally designed as a simple command line, which takes a variable number - an array - of text arguments; from 3 to 7
the original code's declarations are commented; I'm now trying to convert that into a PG shared object function. All of the arguments to the function will be text strings (base command, options, etc.)
how can I declare/pass the array into the function?
PG_FUNCTION_INFO_V1(embed_0);
Datum
embed_0(PG_FUNCTION_ARGS)
// THIS was the declaration when it was a C executable:
// int main(int argc, char *argv[])
{
// don't think mapping argc to a PG type is needed here, right?
// (argc is not a parameter?)
int *argc; // = PG_GETARG_INT32(0);
char argv[] = PG_GETARG_TEXT_P(0);
int i;
Object *pName, *pCall, *pPart1, *pPart2, *pArgs, *pValue;
If you have a variable number of arguments you need to either:
Declare it VARIADIC;
Create n different signatures for the function with different numbers of arguments; or
In C create only the most general form, the 7-argument variety, and then create SQL function wrappers for the fewer-arguments cases that call the most general form.
If you really only need 3,4,5,6, and 7-argument versions I'd do something like:
CREATE FUNCTION embed0(text,text,text,text,text,text,text) RETURNS text
LANGUAGE 'C' AS 'embed0','embed0';
CREATE OR REPLACE FUNCTION embed0(text,text,text) RETURNS text AS $$
SELECT embed0($1,$2,$2,NULL,NULL,NULL,NULL);
$$ LANGUAGE 'SQL';
// ... etc
If 7 args was just an arbitrary upper bound and you can actually take any number of arguments you should instead just write:
CREATE FUNCTION embed0(text,text,text,VARIADIC text) RETURNS text
LANGUAGE 'C' AS 'embed0','embed0';
and handle the variable arguments in your C function. See the PostgreSQL source code for the concat function for how. Its implementation is text_concat in src/backend/utils/adt/varlena.c on line 3842 in current git head; your line number will differ. Most of the work is done in concat_internal.
Another example is the format function, with C implementation text_format (via lookup in pg_proc.h), located in varlena.c (according to git grep '^text_format'; Pg coding style rules specify that the function name must begin on the hard left of the line), line 3953 in current git. While a more complicated function it might be better as an example for you because it does all the work in one place rather than splitting out for a helper function call. It's declared in pg_proc.h but if it were declared in SQL it'd look something like:
CREATE FUNCTION format(text, VARIADIC text) RETURNS text AS 'internal','text_format';
There you'll see that VARIADIC arguments are accessed like any other from C, using the PG_GETARG_...(argno) macros. The PG_NARGS() macro reports the number of arguments passed. VARIADIC arguments may be null so you have to use PG_ARGISNULL(argno) and handle the case of a null argument.
So: I'd write it as a VARIADIC function using PG_NARGS, PG_GETARG_TEXT_P, PG_ARGISNULL. Because Pg's VARIADIC functions cannot be called implicitly with zero variadic arguments, I'd write a wrapper for the 3-argument case that does:
CREATE OR REPLACE FUNCTION embed_0(text,text,text) RETURNS text AS $$
SELECT embed_0($1,$2,$2, VARIADIC ARRAY[]::text[]);
$$ LANGUAGE 'SQL';
, passing an empty array as the variadic parameter. That way you can call it with 3 args too.
BTW, when coding be aware that the string in a Pg text is not null terminated, unlike those passed to main(). You must use the lengths PostgreSQL provides.. See src/include/fmgr.h, the tutorial, and the text handling in the functions in the source code. Don't use strlen, strcat, strcpy, etc because they expect null-terminated strings.
I've had problem when trying write a function which has a default value when no extra arguments are given. I've tried detecting if the only argument given is equal to NULL (as suggested in other answers) but it doesn't seem to be working for me.
The actual implementation of this function takes a struct and adds it to a linked list given in the second argument. If no second argument is given, I want it to add it to a default global linked list which has been previously defined.
Below is a simpler version using int type arguments, but the principle of what I want to do is the same:
/* appropriate headers... */
void test(int a, ... ) {
int b;
va_list args;
va_start(args,a);
b = va_arg(args,int);
if (b == NULL) { // check if no argument is given and set default value
b = 0;
} // if b != NULL then it should be set to the value of the argument
va_end(args);
printf("%d %d\n",a,b);
}
int main() {
test(1);
test(1,1);
return 0;
}
However, this gives the output:
1 *random memory address*
1 1
The output I want should have the first line as
1 0
If I can't use this method then does anyone have any ideas how I can achieve what I want? Thanks in advance.
There is no way to do what you want with just va_list.
You can use macros and __VA_ARGS__ to force a certain argument to show up last in your argument list as a "terminator." i.e.:
#define TEST(a, ...) Test(a, __VA_ARGS__, 0)
Note that I'm using Visual C++. Other compilers might implement __VA_ARGS__ slightly differently so you may need to tweak the implementation.
Your function accepting variable arguments has to be able to tell somehow when it has reached the end of the variable arguments. This can be by parsing information from the fixed arguments (e.g. an argument which tells you how many variable arguments were passed, or a format string which tells you what arguments are supposed to follow), or it can be by an explicit sentinel value, such as a null pointer, at the end of the variable arguments.
You seem to be wanting a major miracle; I'm sorry, only minor miracles are available.
You can design your interfaces like this:
int test1(int x, struct list *list) { ...code to handle adding x to arbitrary list... }
int test0(int x) { return test1(x, &global_struct); }
You then call test0() when you want to use the default list, and test1() when you want specify a different list.
Note that test0() is so simple that it is a good candidate for C99 inline function definition.
If you were using C++ you could provide a function with a default argument or an overloaded function (two argument lists and implementations, as above, but the same name). Of course, even more than in C, the use of global variables is deprecated in C++.
A function has to have some way to know how many arguments it has been given. Your function has no way, so it can't work. You could create two functions. You could have a separate "number of arguments" parameter. You could include some other parameter that indirectly tells it how many parameters it has (like printf uses). But you have to do it somehow.