Exotic C Function Signature Style [duplicate] - c

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.

Related

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

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

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.

Strange function definition [duplicate]

I'm relatively new to C. I've come across a form of function syntax I've never seen before, where the parameter types are defined after that parameter list. Can someone explain to me how it is different than the typical C function syntax?
Example:
int main (argc, argv)
int argc;
char *argv[];
{
return(0);
}
That's the old-style syntax for parameter lists, which is still supported. In K&R C you could also leave off the type declarations and they would default to int. i.e.
main(argc, argv)
char *argv[];
{
return 0;
}
would be the same function.
What's also interesting is the calling convention difference of functions with, and functions without a prototype. Consider an old style definition:
void f(a)
float a; {
/* ... */
}
In this case, the calling convention is that all arguments are promoted before being passed to the function (for example, a float argument is first promoted to double, before being passed). So if f receives a double but the parameter has type float (which is perfectly valid) the compiler has to emit code that converts the double to a float prior to executing the function's body.
If you include a prototype, the compiler does not do such automatic promotions anymore and any data passed is converted to the types of the parameters of the prototype as if by assignment. So the following is not legal and results in undefined behavior:
void f(float a);
void f(a)
float a; {
}
In this case, the function's definition would convert the submitted parameter from double (the promoted form) to float because the definition is old-style. But the parameter was submitted as a float, because the function has a prototype. For example, clang gives
main.c:3:9: warning: promoted type 'double' of K&R function parameter is not compatible with the parameter type 'float' declared in a previous prototype [-Wknr-promoted-parameter]
Your options of solving the contradictions are the two following:
// option 1
void f(double a);
void f(a)
float a; {
}
// option 2
// this declaration can be put in a header, but is redundant in this case,
// since the definition exposes a prototype already if both appear in a
// translation unit prior to the call.
void f(float a);
void f(float a) {
}
Option 2 should be preferred if you have the choice because it gets rid of the old style definition up front. If such contradicting function types for a function appears in the same translation unit, the compiler will usually tell you (but is not required). If such contradictions appear over multiple translation units, the error will possibly go unnoticed and can result in hard to predict bugs. It is best to avoid these old style definitions.
This is the so caller K&R style or old-style declaration.
Note, that this declaration is significantly different from the modern declaration. K&R declaration does not introduce a prototype for the function, meaning that it doesn't expose the types of the parameters to the outside code.
There is no difference, it is just that that is the old syntax for function declarations in C -- it was used pre ANSI. Never write such code unless you plan to give it to your friends from the 80's. Also, never depend upon implicit type assumptions (as another answer seems to suggest)
While the old syntax for function definition still works (with warnings, if you ask your compiler), using them does not provide function prototypes.
Without function prototypes the compiler will not check if the functions are called correctly.
#include <stdio.h>
int foo(c)
int c;
{ return printf("%d\n", c); }
int bar(x)
double x;
{ return printf("%f\n", x); }
int main(void)
{
foo(42); /* ok */
bar(42); /* oops ... 42 here is an `int`, but `bar()` "expects" a `double` */
return 0;
}
When the program is run, the output on my machine is
$ gcc proto.c
$ gcc -Wstrict-prototypes proto.c
proto.c:4: warning: function declaration isn’t a prototype
proto.c:10: warning: function declaration isn’t a prototype
$ ./a.out
42
0.000000
Its just the same but old fashion. You probably found it is some old, legacy code.
Old or not, I would argue what is old and what not.. like the pyramids are ancient, but none of today’s so-called scientists have a clue how they were made. Looking back, old programs still work today without memory leaks, but these "new" programs tend to fail more than often. I see a trend here.
Probably they saw functions as structs which have an executable body. Knowledge of ASM is needed here to solve the mystery.
Edit, found a macro which indicates you do not need to supply argument names at all.
#ifndef OF /* function prototypes */
# ifdef STDC
# define OF(args) args
# else
# define OF(args) ()
# endif
#endif
#ifndef Z_ARG /* function prototypes for stdarg */
# if defined(STDC) || defined(Z_HAVE_STDARG_H)
# define Z_ARG(args) args
# else
# define Z_ARG(args) ()
# endif
#endif
Here is an usage example, library is zlib-1.2.11.
ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
So my second guess would be for function overloading, otherwise these arguments had no use. One concrete function, and now infinite amount of functions with same name.

C function weird syntax [duplicate]

I'm relatively new to C. I've come across a form of function syntax I've never seen before, where the parameter types are defined after that parameter list. Can someone explain to me how it is different than the typical C function syntax?
Example:
int main (argc, argv)
int argc;
char *argv[];
{
return(0);
}
That's the old-style syntax for parameter lists, which is still supported. In K&R C you could also leave off the type declarations and they would default to int. i.e.
main(argc, argv)
char *argv[];
{
return 0;
}
would be the same function.
What's also interesting is the calling convention difference of functions with, and functions without a prototype. Consider an old style definition:
void f(a)
float a; {
/* ... */
}
In this case, the calling convention is that all arguments are promoted before being passed to the function (for example, a float argument is first promoted to double, before being passed). So if f receives a double but the parameter has type float (which is perfectly valid) the compiler has to emit code that converts the double to a float prior to executing the function's body.
If you include a prototype, the compiler does not do such automatic promotions anymore and any data passed is converted to the types of the parameters of the prototype as if by assignment. So the following is not legal and results in undefined behavior:
void f(float a);
void f(a)
float a; {
}
In this case, the function's definition would convert the submitted parameter from double (the promoted form) to float because the definition is old-style. But the parameter was submitted as a float, because the function has a prototype. For example, clang gives
main.c:3:9: warning: promoted type 'double' of K&R function parameter is not compatible with the parameter type 'float' declared in a previous prototype [-Wknr-promoted-parameter]
Your options of solving the contradictions are the two following:
// option 1
void f(double a);
void f(a)
float a; {
}
// option 2
// this declaration can be put in a header, but is redundant in this case,
// since the definition exposes a prototype already if both appear in a
// translation unit prior to the call.
void f(float a);
void f(float a) {
}
Option 2 should be preferred if you have the choice because it gets rid of the old style definition up front. If such contradicting function types for a function appears in the same translation unit, the compiler will usually tell you (but is not required). If such contradictions appear over multiple translation units, the error will possibly go unnoticed and can result in hard to predict bugs. It is best to avoid these old style definitions.
This is the so caller K&R style or old-style declaration.
Note, that this declaration is significantly different from the modern declaration. K&R declaration does not introduce a prototype for the function, meaning that it doesn't expose the types of the parameters to the outside code.
There is no difference, it is just that that is the old syntax for function declarations in C -- it was used pre ANSI. Never write such code unless you plan to give it to your friends from the 80's. Also, never depend upon implicit type assumptions (as another answer seems to suggest)
While the old syntax for function definition still works (with warnings, if you ask your compiler), using them does not provide function prototypes.
Without function prototypes the compiler will not check if the functions are called correctly.
#include <stdio.h>
int foo(c)
int c;
{ return printf("%d\n", c); }
int bar(x)
double x;
{ return printf("%f\n", x); }
int main(void)
{
foo(42); /* ok */
bar(42); /* oops ... 42 here is an `int`, but `bar()` "expects" a `double` */
return 0;
}
When the program is run, the output on my machine is
$ gcc proto.c
$ gcc -Wstrict-prototypes proto.c
proto.c:4: warning: function declaration isn’t a prototype
proto.c:10: warning: function declaration isn’t a prototype
$ ./a.out
42
0.000000
Its just the same but old fashion. You probably found it is some old, legacy code.
Old or not, I would argue what is old and what not.. like the pyramids are ancient, but none of today’s so-called scientists have a clue how they were made. Looking back, old programs still work today without memory leaks, but these "new" programs tend to fail more than often. I see a trend here.
Probably they saw functions as structs which have an executable body. Knowledge of ASM is needed here to solve the mystery.
Edit, found a macro which indicates you do not need to supply argument names at all.
#ifndef OF /* function prototypes */
# ifdef STDC
# define OF(args) args
# else
# define OF(args) ()
# endif
#endif
#ifndef Z_ARG /* function prototypes for stdarg */
# if defined(STDC) || defined(Z_HAVE_STDARG_H)
# define Z_ARG(args) args
# else
# define Z_ARG(args) ()
# endif
#endif
Here is an usage example, library is zlib-1.2.11.
ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
So my second guess would be for function overloading, otherwise these arguments had no use. One concrete function, and now infinite amount of functions with same name.

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