The following code does not emit any warnings when compiled with both gcc and clang on Linux x64:
#include <stdio.h>
#include <stdlib.h>
void foo(void);
void foo(void);
void foo(void);
int main(void)
{
return 0;
}
IMO, it's legal according to the following snippets from C99:
All declarations that refer to the same object or function shall have
compatible type; otherwise, the behavior is undefined.
(...)
For two function
types to be compatible, both shall specify compatible return types
(...)
Moreover, the parameter type lists, if both are present, shall agree in the
number of parameters and in use of the ellipsis terminator; corresponding
parameters shall have compatible types.
(...)
Two types have compatible type if their types are the same.
Am I right? I want to make sure it is not UB and that my understanding is correct.
Multiple identical prototypes are legal, and in fact common, because it is typical in modern C for a function definition to comprise a prototype for that function, and for there also to be a prototype for the function in scope from inclusion of a header file. That is, given
foo.h:
void foo(int x);
foo.c:
#include "foo.h"
void foo(int x) {
printf("%d\n", x);
}
/* ... */
there are two identical prototypes for foo() in scope in the body of function foo's definition and throughout the rest of the file. This is fine.
It is also ok to have multiple declarations of the same object or function that are not identical, as long as they are compatible. For example, the
declaration
void foo();
declares foo as a function taking unspecified parameters and returning nothing. This declaration is compatible with the ones already present in foo.c and foo.h, and it could be added to either one or both of those files with zero additional effect.
And this all applies to objects (variables), too, where some applications are quite common. For example, if you want to declare a global variable that is accessed from multiple files, then it is common to put a declaration of that variable in a header file. The C source file containing and the definition of that variable -- which is also a declaration -- typically #includes the header, yielding two declarations:
global.h:
extern int global;
global.c:
#include "global.h"
int global = 42;
Or there is the case of forward declaration of compound data types:
struct one;
struct two {
struct one *my_one;
struct two *next;
};
struct one {
struct two *my_two;
}
Note the multiple compatible, but not identical, declarations of struct one. This particular set of data structures cannot be declared at all without multiple declaration of one of the types.
Related
This code will compile and is well defined under current C standards:
static int foo(int);
extern int foo(int);
The standard specifies that in this situation (C11: 6.2.2 Linkages of identifiers (p4)):
For an identifier declared with the storage-class specifier extern in
a scope in which a prior declaration of that identifier is visible,31)
if the prior declaration specifies internal or external linkage, the
linkage of the identifier at the later declaration is the same as the
linkage specified at the prior declaration. [...]
... which means that the int foo(int) function is declared static int foo(int).
Swapping these declarations around like this:
extern int foo(int);
static int foo(int);
...gives me a compiler error using GNU GCC:
static declaration of 'foo' follows non-static declaration
My question is: What is the design rationale behind the second case being an error and not handled in a similar way as the first case? I suspect it has something to do with the fact that separate translation units are easier to manage and #include? I feel as though without understanding this, I can open myself up to some mistakes in future C projects.
I think the idea of this confusing specification is that an extern declaration can be used inside a function to refer to a global function or object, e.g to disambiguate it from another identifier with the same name
static double a; // a declaration and definition
void func(void) {
unsigned a;
.....
if (something) {
extern double a; // refers to the file scope object
}
}
Whereas if you use static you declare something new:
extern double a; // just a declaration, not a definition
// may reside elsewhere
void func(void) {
unsigned a;
.....
if (something) {
static double a; // declares and defines a new object
}
}
I can imagine that the scenario leading to this asymmetry is that the default linkage of identifiers at global scope is extern.1 Failing to mark the definition of a previously static-declared function static as well would otherwise be an error because it is by default also an extern declaration.
Here is an illustration. In modern C, functions must be declared before use, but sometimes the implementation is at the end because it is secondary to the main purpose of the code in the file:
static void helper_func(); // typically not in a header
// code using helper_func()
// And eventually its definition, which by default
// declares an **external** function. Adding
// an explicit `extern` would not change a thing; it's redundant.
void helper_func() { /* ... */ }
This looks innocent enough, and the intent is clear. When C was standardized there was probably code around looking like this. That's why it is allowed.
Now consider the opposite:
extern void func(); // this could be in a header
// ... intervening code, perhaps a different file ...
static void func() { /* ... */ }
// code which uses func()
It's pretty clear that this should not be allowed. Defining a function static is a clear, explicit statement. A prior, contradicting extern declaration does not make sense.2 There is a good chance that this is an inadvertent name collision, for example with a function declared in a header. Probably not much code out there was looking like this at the time of formalization. That's why it is forbidden.
1 From the C17 draft, 6.2.2/5: "If the declaration of an identifier for a function has no storage-class specifier, its linkage is determined exactly as if it were declared with the storage-class specifier extern."
2 One could argue that an explicit extern declaration using the keyword, followed by a static definition, should be forbidden while an implicit one, without the keyword, could still be allowed (and that, correspondingly, a later explicitly extern function definition after a static declaration should be forbidden, while implicit ones are still allowed). But there is a limit to the hair-splitting a standard should do (and it's gone pretty far already).
This question already has answers here:
How do I use extern to share variables between source files?
(19 answers)
Closed 8 years ago.
file1.c => includes file1.h
file1.h => has a struct:
typedef struct {
unsigned char *start;
unsigned int startInt;
}debugPrint;
file1.c => creates a struct object:
debugPrint dp;
file1.c => an int is given into struct:
dp.startInt = 10;
file1.c => has a function:
void function1(debugPrint dp) {
printf("%d", dp.startInt);
}
file2.h => has a function call to file1.c function which is declared before the call:
void function1(void);
function1();
Questions is:
Is it ok that the file2.h calls a function from file1.c
how can i pass the dp.startInt value to file2.h so that the value 10 that was set into dp.startInt in file1.c can be used in the funtion call in file2.h ?
It is needed to be called from file2.h since this file handles dynamic variable exchange between a html page and the file2.h file => data from file2.h function call via file1.c is sent to Html page. But i wont go more into the passing variable to html page since i don't know how it is made. It is a mechanism of openPicus web server example.
But if you know a good solution for this one. i would appreciate it. I'm not so familiar with this kind of code so that is also an issue here :)
But since i think this description is not good enough, here is the files:
file1.c:
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#include "test1.h"
// Define printStruct
void printStruct (debugPrint dp) {
printf("%u", dp.startInt);
}
int main ()
{
dp.startInt = 10;
getch();
}
file1.h:
typedef struct {
// For the motorEncoder value
unsigned char filename[20];
char ownMsg[10];
unsigned char *start;
unsigned char *timeInSeconds;
unsigned char *distanceInCm;
unsigned char *numberOfShots;
unsigned char *shutterCompensation;
unsigned char *direction;
unsigned char *cancel;
unsigned char *dutyCycle;
unsigned int cancelInt;
unsigned int startInt;
unsigned int dutyCycleInt;
unsigned int directionInt;
}debugPrint;
// Create struct object called dp
debugPrint dp;
// declare printStruct
void printStruct (debugPrint dp);
file2.h: (this file is totally needed to pass the dynamic values) I didn't put any includes since im not sure how i should include the .h files and from where i should include them.
// Call printStruct function
printStruct(dp);
part of file2.h actual code: (AND YES file2.h A HEADER FILE). FOR ME THIS SEEMS LIKE THE FUNCTIONS ARE FIRST DECLARED AND THEN ONE OF THEM IS USED IN THE H FILE => the HTTPPrint() function from where a function called HTTPPrint_stepCounter(); is called. That function is defined then in file1.c and it just prints some dynamic data to a http page. And as said this is how openPicus has done it and i am just trying to modify it.
void HTTPPrint(DWORD callbackID);
void HTTPPrint_led(WORD);
void HTTPPrint_stepCounter(void);
void HTTPPrint(DWORD callbackID)
{
switch(callbackID)
{
case 0x00000017:
HTTPPrint_led(0);
break;
case 0x00000059:
HTTPPrint_stepCounter();
break;
default:
// Output notification for undefined values
TCPPutROMArray(sktHTTP, (ROM BYTE*)"!DEF", 4);
}
return;
}
void HTTPPrint_(void)
{
TCPPut(sktHTTP, '~');
return;
}
Some tips for someone new to the C language:
There's an important difference between definition and declaration.
Definition is what actually creates the function or variable. Each function must be defined exactly once. Either in a *.c source file, or in a library.
Declaration creates an entry in the symbol table, that says the function or variable exists... somewhere... and here's its data type. Declarations can be duplicated without any effect.
We put function definitions in *.c source files. (And also in libraries, but that's an advanced build topic...)
We put public or extern function declarations in *.h header files.
We put shared extern variable declarations in *.h header files, so that other source units can share the same variable.
We put shared typedef structure declarations in *.h header files, so that other source units can share the same data type.
We do not put variable declarations in *.h header files if they aren't extern, or if they are initialized. The initial value belongs in the *.c file.
Function definitions usually don't belong in a *.h header file, because it's possible in a large project, that the header file could be included (read by the compiler) more than once. That would cause a compiler error, because then there would be more than one definition of that function. Even if it's literally a repeat of the same source code, there can be only one.
The quote about file2.h having a function call to file1.c function is not correct, function1(); could be either a declaration or a function call depending on context:
// declaration of a function named foo
void foo(void);
//
// declaration of a function named bar
// equivalent to declaring void bar(void);
bar();
//
// definition of a function named foo
void foo(void)
{
// call (or invoke) the function named bar
bar();
}
Another small point, about arrays: it's pretty strange to declare an array of one element debugPrint dp[1], since that declaration creates an object that will be referred to as dp[0]. This makes me think you may be trying to avoid the use of pointers... it would be more straightforward to just declare debugPrint dp and then the object is referred to as dp. Arrays make sense if you have more than one related object of the same type, but for just one object, it's a pretty unusual usage.
C is a very flexible programming language that gives free access to lots of low-level tricks. Both a blessing and a curse... For someone just getting started with the language, it's important to read other people's code examples as much as you can, to help learn how things are usually done. There are lots of extremely clever ways to use the language (e.g. Duff's Device) but in most cases, you're better off sticking with the most straightforward and customary way of solving the problem.
See also: What is the difference between a definition and a declaration?
You claim that file2.h contains:
void function(void);
function1();
But these lines refer to two different functions.
This problem is now fixed; both names are function1
If the function1(); appears outside any function, it is a (very sloppy) function declaration, not a function call. If it is inside some function, what is that function definition doing inside the header file. It would need to be an inline function to have much legitimacy.
The problem below is now fixed; the types are consistent.
Additionally, you say: an integer is given into struct: dp[1].startInt = 10;. The compiler complains that you shouldn't assign integers to pointers (since startInt is declared as a pointer, not an int). You need to get your code to compile without such complaints.
... There are two versions of the structure defined, one at the top of the question where startInt is an unsigned int *startInt; and one later on where the declaration is unsigned int startInt. Please make your question self-consistent! ...
This problem has been fixed now; dp is a simple structure.
Also note that you created debugPrint dp[1]; so your initialization is trampling out of bounds; the maximum valid index for the array is 0.
If code in file2.c needs to access the internals of the structure type declared in file1.h, the header file1.h should be included in file2.c. You can declare your dp array in the header too. A header should include other headers only if the functions it defines expose types defined in the other headers. For example, if the structure defined in file1.h included a FILE *db_fp; element, then file1.h should #include <stdio.h> to ensure that the code in file1.h would compile regardless of what else the code using file1.h includes.
A little bit of context first. My program features a header, work.h. This header contains a structure, some function definitions, and an extern array of pointers to my base functions.
work.h
typedef struct _foo {
int id;
char something[20];
} foo;
typedef void (*pointer_function)(foo *);
void do_first_to_foo(foo *);
void do_second_to_foo(foo *);
void do_third_to_foo(foo *);
extern pointer_function base_functions[3];
Then a program called work.c with the bodies of the functions, and then the main program main.c. Observe in the header work.h that I have defined prototypes of three functions, and the size of the array is 3, so the pointers on the extern array will point to each one of the 3 functions.
My questions are, how I can associate the pointers of the extern array with the three functions, and second, in which file I need to do it (work.c or main.c).
I understand this association I need to do it in the file work.c, but nothing else.
In work.c:
#include "work.h"
pointer_function base_functions[] = {
do_first_to_foo,
do_second_to_foo,
do_third_to_foo };
Explanation: that array name is a global symbol, and needs to be actually defined in just one compilation unit (.o file produced from .c file). If you do not have it, linker will not find it. If you have multiple copies, linker will complain. You need just one, same as with global exported functions (which are not marked inline).
Edit: Added showing #include "work.h", which is important because it allows compiler to check that extern declaration matches the actual definition. If you leave it out, everything will compile and link without complaints, but you get no indication if there's a mismatch, which could wreak havoc like corrupt other data in memory when variable is used in other compilation units.
This is file "1.c"
#include <stdio.h>
char foo;
int bar(){
}
int main(){
printf("%d",foo);
return 0;
}
//--------------------------
This is file '2.c'
void foo(){
}
Compiler invoked as gcc 1.c 2.c
Does the above gives an undefined behaviour? My guess is, yes. Otherwise it's almost impossible to do optimization.
Multiple different definitions for the same entity (class, template, enumeration, inline function, static member function, etc.) [What are all the common undefined behaviour that a C++ programmer should know about?
But as far as I know char foo produce only a weak symbol that can be overridden by void foo(){} at linkage. Furthermore, if I change char foo into extern char foo, is that still a definition?
It'd cause undefined behaviour, yes. There are probably lots of quotes from the standard that are explicit for the various types of declarations and so forth, but this sums it up:
In the set of translation units and libraries that constitutes an entire program, each
declaration of a particular identifier with external linkage denotes the same object or
function. (6.2.2)
All declarations that refer to the same object or function shall have compatible type;
otherwise, the behavior is undefined. (6.2.7)
char foo; in your example is a tentative definition. If you use extern, it would not be a definition, but it'd still be a declaration, and the above would still apply.
I have a library I created,
File mylib.c:
#include <mylib.h>
int
testlib() {
printf("Hello, World!\n");
return (0);
}
File mylib.h:
#include <stdio.h>
extern int testlib();
In my program, I've attempted to call this library function:
File myprogram.c:
#include <mylib.h>
int
main (int argc, char *argv[]) {
testlib();
return (0);
}
When I attempt to compile this program I get the following error:
In file included from myprogram.c:1
mylib.h:2 warning: function declaration isn't a prototype
I'm using: gcc (GCC) 3.4.5 20051201 (Red Hat 3.4.5-2)
What is the proper way to declare a function prototype?
In C int foo() and int foo(void) are different functions. int foo() accepts an arbitrary number of arguments, while int foo(void) accepts 0 arguments. In C++ they mean the same thing. I suggest that you use void consistently when you mean no arguments.
If you have a variable a, extern int a; is a way to tell the compiler that a is a symbol that might be present in a different translation unit (C compiler speak for source file), don't resolve it until link time. On the other hand, symbols which are function names are anyway resolved at link time. The meaning of a storage class specifier on a function (extern, static) only affects its visibility and extern is the default, so extern is actually unnecessary.
I suggest removing the extern, it is extraneous and is usually omitted.
Quick answer: change int testlib() to int testlib(void) to specify that the function takes no arguments.
A prototype is by definition a function declaration that specifies the type(s) of the function's argument(s).
A non-prototype function declaration like
int foo();
is an old-style declaration that does not specify the number or types of arguments. (Prior to the 1989 ANSI C standard, this was the only kind of function declaration available in the language.) You can call such a function with any arbitrary number of arguments, and the compiler isn't required to complain -- but if the call is inconsistent with the definition, your program has undefined behavior.
For a function that takes one or more arguments, you can specify the type of each argument in the declaration:
int bar(int x, double y);
Functions with no arguments are a special case. Logically, empty parentheses would have been a good way to specify that a function takes no arguments, but that syntax was already in use for old-style function declarations, so the ANSI C committee invented a new syntax using the void keyword:
int foo(void); /* foo takes no arguments */
A function definition (which includes code for what the function actually does) also provides a declaration. In your case, you have something similar to:
int testlib()
{
/* code that implements testlib */
}
This provides a non-prototype declaration for testlib. As a definition, this tells the compiler that testlib has no parameters, but as a declaration, it only tells the compiler that testlib takes some unspecified but fixed number and type(s) of arguments.
If you change () to (void) the declaration becomes a prototype.
The advantage of a prototype is that if you accidentally call testlib with one or more arguments, the compiler will diagnose the error.
(C++ has slightly different rules. C++ doesn't have old-style function declarations, and empty parentheses specifically mean that a function takes no arguments. C++ supports the (void) syntax for consistency with C. But unless you specifically need your code to compile both as C and as C++, you should probably use the () in C++ and the (void) syntax in C.)
Try:
extern int testlib(void);