What happens to the unspecified arguments in function()? [duplicate] - c

This question already has answers here:
What does an empty parameter list mean? [duplicate]
(5 answers)
Accessing the parameters passed to a function with an empty parameter list in C
(2 answers)
Closed 2 years ago.
I have been reading the difference between function() and function(void) in C, and I came to know that
an empty parameter list in a function declaration indicates that the
function takes an unspecified number of parameters
So I ran this code:
#include <stdio.h>
void fun();
int main(void)
{
fun(12, 13.22, 1234567890987654321, "wow", 'c');
}
void fun()
{
printf("What happened to those arguments?");
}
I don't understand why C allows this. All the posts I've read so far related to this say things like it's bad practice to use it, it is obsolescent, etc. Also from the above code, I think the type of those arguments is also unspecified. So I just want to know the reason behind "unspecified arguments of unspecified type":
What can be done with those arguments?
Is it possible to access those arguments within the function?

The reason for supporting the notation is historical. Before the first C standard (C89/C90), you couldn't use prototypes in C; prototypes were one of the biggest and most important features of Standard C. All function declarations, therefore, were written the 'empty parentheses' style (when they were written at all; most functions that returned int were not declared at all). The type void was also added in C89/C90, though some compilers supported it before the standard was finalized.
Because it was crucial to the success of C89/C90 that existing code should mostly continue to work, the empty parentheses style had to be allowed by the standard. So, your code might have been written in pre-standard C as:
#include <stdio.h>
int fun(); /* This declaration would probably have been absent */
int main(void)
{
fun(12, 13.22, 1234567, "wow", 'c');
return 0; /* This was required until C99 to give reliable exit status */
}
fun(i, d, l, s, c) /* No return type - implicitly returns int */
long l; /* Defined out of sequence - bad style, but legal */
char c; /* Passed as int; converted to char in function */
char *s; /* Should define all pointer arguments */
double d; /* No definition of i; it was an int by default */
{
printf("This is what happened to those arguments:\n");
printf("i = %d\n", i);
printf("d = %f\n", d);
printf("l = %ld\n", l);
printf("s = [%s]\n", s);
printf("c = %c\n", c);
/* No return statement - don't use the value from the function */
}
For the curious: you could omit the char *s; line in the function definition, and it still compiled and produced the same output. It was a bad idea to try that, though. You could replace the line int fun(); with static fun(); and the code compiles cleanly when no diagnostics are requested.
You get no warnings even now if you compile this file (old31.c) with GCC 9.3.0 using:
$ gcc -std=c90 -o old31 old31.c
$
Your example as written is skirting around the backwards compatibility provisions. Using void means it was new code (it would not have been valid in many pre-standard C compilers because it used void). And new code should not exploit the backwards-compatibility provisions without a good reason. That was true in 1991 as well as in the current millennium (but in 1991, there were a lot more good reasons to exploit the backwards-compatibility provisions). Good pre-standard code usually listed all parameters in the order they were used. Omitted definitions and out of sequence definitions were not entirely satisfactory.
You asked:
What can be done with those arguments?
In the code in the question, nothing can be done with the arguments. The caller pushes the values onto the stack, and pops them off when the function returns. The called function is unaware of their existence and can do nothing with them.
Is it possible to access those arguments within the function?
No — not using any standard mechanism.

There is a difference between a function declaration and a function definition when there is an empty parameter list.
Section 6.7.6.3p14 of the C standard states:
An identifier list declares only the identifiers of the parameters of
the function. An empty list in a function declarator that is
part of a definition of that function specifies that the
function has no parameters. 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.
What this means is that this declaration:
void fun();
Means fun takes an unknown number of parameters. While this definition:
void fun()
{
printf("What happened to those arguments?");
}
Means that fun takes no parameters. So this function call:
fun(12, 13.22, 1234567890987654321, "wow", 'c');
Is invalid and invoked undefined behavior because the number of parameters in the call don't match the actual number of parameters. This is spelled out in section 6.5.2.2p6 regarding the function call operator ():
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.
As for why this is allowed, it is legacy behavior that goes back to pre-standardized versions of C where the type of variables and the return type of functions defaulted to int and the method of declaring functions differed from what they are now.

Related

Why does a function that returns int not need a prototype?

I tried this program on DevC++ that would call two different types of function, one returning int and one returning char. I'm confused why the int function doesn't need a prototype, while the char one and any other type of function does.
#include <stdio.h>
//int function1();
char function2() ;
int main (){
int X = function1() ;
char Y = function2() ;
printf("%d", X) ;
printf ("%c", Y) ;
return 0 ;
}
int function1(){
return 100 ;
}
char function2(){
return 'B' ;
}
The output:
100B
If I remove the prototype for the char function, it results in:
[Error] conflicting types for 'function2'
[Note] previous implicit declaration of 'function2' was here
In the old days of C any function that was not declared explicitely was supposed to return int type when you call it.
If the compiler then finds the function implementation and sees an int return type, everything is fine.
If the function returns anything else than int you get the error message as you saw with the second function.
This implicit int type declaration was removed from the standard with C99. Now you should at least get a warning from your compiler when you use a function without prototype.
If you did not get any diagnostic message for first funcion, you should turn up warning level in your compiler or switch to at least C99 mode instead of ancient versions.
Edit:
Empty parameter lists in funcion definitions is a deprecated feature as well.
You should not use it.
Always provide prototype for every function with return type and parameter list.
If a function is used before it is declared, the usage becomes an implicit declaration of the function. When a function f is implicitly defined, the definition given to it is int f(), i.e. a function which accepts an unspecified number of arguments and returns an int.
This implicit definition of a function matches the actual definition of function1 but not function2. So calling function1 this way gives no error but attempting to call function2 this way results in the implicit definition not matching the actual definition, giving an error.
This behavior goes back to pre-standardized versions of C where all objects (and a function's return type) had a default type of int if not declared. This was still present in the C89 standard but removed in the C99 standard, although some compilers such as gcc still support this obsolescent usage as an extension.
It's just an ancient relic from when C was first designed. It was actually removed as early as C99, but many compilers still support this type of declaration. But it's not recommended to use it.
I'm not sure if there were any real rationale behind it, but C was heavily inspired by the language B. And in B you did not have to specify the return type for functions. That actually made perfect sense, because there was only one type, word.
In the same way you did not have to specify the type of variables either. You only specified if it had automatic or static storage. And that's where the completely useless keyword auto in C comes from. It does not mean the same as in C++. It just means "not static".

Calling method without typeless argument

I have noticed some behavior in C that I do not quite understand. If I define a function with an argument that I do not specify a type for and call it without any argument, the code compiles but gives a warning that the type of the parameter defaults to int.
void f(i) {
printf("%d", i);
}
int main(void) {
f();
}
If I run this on godbolt, I get the expected compiler warning, and execution prints 1 to stdout.
However, if I define the same method, but explicitly declare the argument as an int, the compiler throws an error for the function being called with too few arguments.
void f(int i) {
printf("%d", i);
}
int main(void) {
f();
}
Compiling this on godbolt produces error: too few arguments to function 'f'.
This behavior is consistent across all modern versions of gcc and clang. Why does specifying the type of the argument make this a compiler error? Also, is the behavior of the first example defined? The fact that gcc and clang both always make i 1 would make me think that this is intentional. If so, why?
The second piece of code is relatively simple. The function is defined to accept one argument, and the function call in main passed no arguments. That's a clear error.
The first piece of code is more interesting. This goes back to old style function definitions where the parameter list contains only the names of the parameters and the types appear between the closing parenthesis terminating the argument list and the opening brace before the start of the function body. Such a function properly defined would look like this:
void f(i)
int i;
{
printf("%d", i);
}
This style of specifying function arguments dates back to the original K&R C but is considered deprecated now. This variant of C also had the property that the type of a variable could be omitted in which cast it defaults to int.
However, even if you do specify the type after the argument list as in the above example, it's still not an error. So why is this?
The key parts comes from section 6.5.2.2 of the C standard regarding function calls:
2 If the expression that denotes the called function has a type that includes a prototype, the number of arguments shall agree with the number of parameters. Each argument shall have a type such that its value may be assigned to an object with the unqualified version of the type of its corresponding parameter.
...
8 No other conversions are performed implicitly; in particular, the number and types of arguments are not compared with those of the parameters in a function definition that does not include a function prototype declarator.
And section 6.9.1p7 regarding function definitions:
The declarator in a function definition specifies the name of the function being defined and the identifiers of its parameters. If the declarator includes a parameter type list, the list also specifies the types of all the parameters; such a declarator also serves as a function prototype for later calls to the same function in the same translation unit. If the declarator includes an identifier list, the types of the parameters shall be declared in a following declaration list. In either case, the type of each parameter is adjusted as described in 6.7.6.3 for a parameter type list; the resulting type shall be a complete object type
In the case of a K&R style function definition, the parameters are specified as an identifier list as opposed to a parameter type list. This means that the function definition does not also specify a function prototype, meaning the number and types of the parameters are not checked when the function is called.
There are two types of function prototypes:
The original, known as "K&R" [from Kernighan & Ritchie, the creators of C].
The modern, known as "ANSI" [from the ANSI standardization committee].
At first, we only had K&R:
#include <stdio.h>
void
f(i)
int i;
{
printf("%d\n",i);
}
int
main(void)
{
f();
return 0;
}
When the C language was standardized, an alternate form of function prototype was added:
#include <stdio.h>
void
f(int i)
{
printf("%d\n",i);
}
int
main(void)
{
f();
return 0;
}
These are how the functions are defined. But, if we put f in a separate file, we'd be left with the prototype declarations:
Here is K&R:
#include <stdio.h>
void f();
int
main(void)
{
f();
return 0;
}
Here is ANSI:
#include <stdio.h>
void f(int i);
int
main(void)
{
f();
return 0;
}
If you look closely at the K&R prototype, there is no way to discern the type for i.
That blemish was rectified with ANSI. If you look at that prototype, the type is for i is explicitly specified as int.
So, to answer your question, in your examples, the syntax without the int is a K&R style prototype/definition. When we add int, it is an ANSI prototype/definition.
K&R hasn't been widely used in new code since sometime in the 1990's (IIRC). But, the compilers understand it for backward compatibility with code written pre-ANSI.
Side note: I started programming in C in 1981, so I was using K&R for at least a decade (A lot of this post comes from [fading] memory). After I got a compiler that supported ANSI, after a few months trying out the ANSI prototypes on new code, I converted all my old code to use ANSI.
For more information ...
See: Function declaration: K&R vs ANSI
And, Alternative (K&R) C syntax for function declaration versus prototypes

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

Exotic C Function Signature Style [duplicate]

This question already has answers here:
Alternative (K&R) C syntax for function declaration versus prototypes
(5 answers)
Closed 6 years ago.
What are the differences between a K&R function declaration and an ANSI function declaration?
K&R syntax is obsolete, you can skip it unless you have to maintain very old code.
// K&R syntax
int foo(a, p)
int a;
char *p;
{
return 0;
}
// ANSI syntax
int foo(int a, char *p)
{
return 0;
}
Legacy K&R-Style Declarations/Definitions
When Kernighan and Ritchie first published "The C Programming Language", C didn't yet offer full function prototypes. Forward declarations of functions existed, but with the sole purpose of indicating a return type. For functions that returned int, they weren't required until C99.
By C89, the notion of a function prototype, which also specifies the types of the parameters (and, implicitly, their number) had been added. Since a prototype is also a type of function declaration, the unofficial term "K&R function declaration" is sometimes used for a function declaration that is not also a prototype.
// K&R declarations, we don't know whether these functions have parameters.
int foo(); // this declaration not strictly necessary until C99, because it returns int
float bar();
// Full prototypes, specifying the number and types of parameters
int foo(int);
float bar(int, float);
// K&R definition of a function
int foo(a)
int a; // parameter types were declared separately
{
// ...
return 0;
}
// Modern definition of a function
float bar(int a, float b)
{
// ...
return 0.0;
}
The Accidental K&R Declaration
It's worth noting that newcomers to C may accidentally use K&R declarations when they intend to use a full prototype, because they may not realize that an empty parameter list must be specified as void.
If you declare and define a function as
// Accidental K&R declaration
int baz(); // May be called with any possible set of parameters
// Definition
int baz() // No actual parameters means undefined behavior if called with parameters.
// Missing "void" in the parameter list of a definition is undesirable but not
// strictly an error, no parameters in a definition does mean no parameters;
// still, it's better to be in the habit of consistently using "void" for empty
// parameter lists in C, so we don't forget when writing prototypes.
{
// ...
return 0;
}
...then you have not actually given a prototype for a function that takes no parameters, but a declaration in K&R-style for a function that accepts an unknown number of parameters of unknown type.
AnT notes in this answer to a similar question that this syntax is deprecated but still legal as of C99 (and that function pointers to functions with unknown number and type of parameters still have potential applications, though at high risk of undefined behavior); as such, compliant compilers will, at best, produce a warning if a function is declared or called without a proper prototype.
Calling functions without prototypes is less safe, because the compiler cannot verify that you have passed the correct number and types of parameters in the correct order; undefined behavior results if the call is not actually correct.
The correct way to declare and define a parameterless function is, of course:
// Modern declaration of a parameterless function.
int qux(void); // "void" as a parameter type means there are no parameters.
// Without using "void", this would be a K&R declaration.
// Modern definition of a parameterless function
int qux(void)
{
// ...
return 0;
}
I just want to add that in the traditional K & R style type modifiers for functions that return an int value aren't even necessary.
Consider the modern C11 notation of a simple HelloWorld program:
int main(int argc, char **argv) {
printf("hello world\n");
return 0;
}
This is equivalent to the K & R notation style:
main(argc, argv)
int argc;
char **argv;
{
printf("hello world\n");
return 0;
}
Note that the int before main() is ignored, but the code still compiles. That's a part of the K & R definition.
Quote Wikipedia:
In early versions of C, only functions that returned a non-int value needed to be declared if used before the function definition; a function used without any previous declaration was assumed to return type int, if its value was used.
--source: https://en.wikipedia.org/wiki/C_(programming_language)#K.26R_C
This is arguably a legacy coding-style and should be avoided due to clarity issues, but quite often old algorithm textbooks favour this sort of K & R style.

Function declaration: K&R vs ANSI [duplicate]

This question already has answers here:
Alternative (K&R) C syntax for function declaration versus prototypes
(5 answers)
Closed 6 years ago.
What are the differences between a K&R function declaration and an ANSI function declaration?
K&R syntax is obsolete, you can skip it unless you have to maintain very old code.
// K&R syntax
int foo(a, p)
int a;
char *p;
{
return 0;
}
// ANSI syntax
int foo(int a, char *p)
{
return 0;
}
Legacy K&R-Style Declarations/Definitions
When Kernighan and Ritchie first published "The C Programming Language", C didn't yet offer full function prototypes. Forward declarations of functions existed, but with the sole purpose of indicating a return type. For functions that returned int, they weren't required until C99.
By C89, the notion of a function prototype, which also specifies the types of the parameters (and, implicitly, their number) had been added. Since a prototype is also a type of function declaration, the unofficial term "K&R function declaration" is sometimes used for a function declaration that is not also a prototype.
// K&R declarations, we don't know whether these functions have parameters.
int foo(); // this declaration not strictly necessary until C99, because it returns int
float bar();
// Full prototypes, specifying the number and types of parameters
int foo(int);
float bar(int, float);
// K&R definition of a function
int foo(a)
int a; // parameter types were declared separately
{
// ...
return 0;
}
// Modern definition of a function
float bar(int a, float b)
{
// ...
return 0.0;
}
The Accidental K&R Declaration
It's worth noting that newcomers to C may accidentally use K&R declarations when they intend to use a full prototype, because they may not realize that an empty parameter list must be specified as void.
If you declare and define a function as
// Accidental K&R declaration
int baz(); // May be called with any possible set of parameters
// Definition
int baz() // No actual parameters means undefined behavior if called with parameters.
// Missing "void" in the parameter list of a definition is undesirable but not
// strictly an error, no parameters in a definition does mean no parameters;
// still, it's better to be in the habit of consistently using "void" for empty
// parameter lists in C, so we don't forget when writing prototypes.
{
// ...
return 0;
}
...then you have not actually given a prototype for a function that takes no parameters, but a declaration in K&R-style for a function that accepts an unknown number of parameters of unknown type.
AnT notes in this answer to a similar question that this syntax is deprecated but still legal as of C99 (and that function pointers to functions with unknown number and type of parameters still have potential applications, though at high risk of undefined behavior); as such, compliant compilers will, at best, produce a warning if a function is declared or called without a proper prototype.
Calling functions without prototypes is less safe, because the compiler cannot verify that you have passed the correct number and types of parameters in the correct order; undefined behavior results if the call is not actually correct.
The correct way to declare and define a parameterless function is, of course:
// Modern declaration of a parameterless function.
int qux(void); // "void" as a parameter type means there are no parameters.
// Without using "void", this would be a K&R declaration.
// Modern definition of a parameterless function
int qux(void)
{
// ...
return 0;
}
I just want to add that in the traditional K & R style type modifiers for functions that return an int value aren't even necessary.
Consider the modern C11 notation of a simple HelloWorld program:
int main(int argc, char **argv) {
printf("hello world\n");
return 0;
}
This is equivalent to the K & R notation style:
main(argc, argv)
int argc;
char **argv;
{
printf("hello world\n");
return 0;
}
Note that the int before main() is ignored, but the code still compiles. That's a part of the K & R definition.
Quote Wikipedia:
In early versions of C, only functions that returned a non-int value needed to be declared if used before the function definition; a function used without any previous declaration was assumed to return type int, if its value was used.
--source: https://en.wikipedia.org/wiki/C_(programming_language)#K.26R_C
This is arguably a legacy coding-style and should be avoided due to clarity issues, but quite often old algorithm textbooks favour this sort of K & R style.

Resources