I'm working on a project in which I'm forced to use some previously written code that uses many header files calling other header files. I'm trying to keep my application separated, but I still need to use many of the types and functions defined in the previous code.
I've added forward declarations in my own header files, when referencing data types declared in other header files. My problem now, is I'm trying to reference a union type from within a function definition in a source file and I'm not quite sure how to do it.
Old header file:
/* filename: include.h */
typedef union SOME_UNION_TYPE
{
int a;
.
.
}SOME_UNION_TYPE;
My source file:
/* filename: file.c */
void func()
{
SOME_UNION_TYPE A;
.
.
return;
}
I know it would be easier to just include "include.h" in my source code, but I'm trying to avoid it as much as possible. My attempt so far has been to forward declare the union in my header file, in hopes of exposing the typedef name to the compiler.
My header file:
/* filename: file.h */
union SOME_UNION_TYPE;
However, when I compile, I receive an error complaining about unknown size for A in func().
Thanks in advance for any help.
If you need to create an actual instance of the type, you need the complete declaration, not just the name.
The right thing to do in this case is to bite the bullet and include the header file that defines the type.
The #include directive is not something to be avoided. If you're concerned about other people's code polluting your code, you can make a header that includes the headers you need, and include that one directly.
Duplicating code is bad.
The other code probably includes a bunch of other headers because it needs them! You should just include the other header otherwise you are duplicating code which is bad.
Related
I double-checked all the similar questions here, I really hope not to duplicate.
I am intrigued by the the following extract from stdio.h:
typedef struct _iobuf {
/* Members here omitted ... */
} FILE;
extern FILE _iob[20];
We define a new type named FILE by using the struct syntax. Just after that, we declare an extern variable _iob of type FILE. Therefore, this variable must come from another place.
But, since the definition of FILE is in this file, how can it be possible? I see two possibilities only.
The first is to have something like:
#include <stdio.h>
FILE _iob[20] = /* definition */
The second is to have another source file where the struct is copy-pasted and the variable declared, I guess a very bad practice that we can omit.
Since I am a self-learner, I would be very happy to receive a confirm of my understanding.Thanks!
Either:
somewhere in the library source code files, there is text as you describe, an inclusion of <stdio.h> followed by a definition of FILE _iob[20], or
somewhere in the library source code files, there is a definition of _iob written in a programming language other than standard C.
The latter may be assembly language, non-standard C with extensions, or something else. An implementation of C is not required to use only C source code to define itself.
In general, it is good practice for the source file that defines an object to also include its own header. A primary purpose of a header file is to tell other source files about things defined in the associated source file. But including the header file in the source file serves another purpose: The compiler will see both the declarations in the header and the definitions in the source file and will issue error messages if they are incompatible. So this provides a check that catches typos or other errors when building the library.
I'm writing a c project and I'm trying to keep all the struct declarations in the relevant .h files. This allows me to use them in any of the .c files by including the relevant header.
I'm also avoiding the inclusion of header files of my project in other header files. I guess this will make the code easier to read and maintain.
My question is how to avoid the inclusion of a header which contains the declaration of a struct in the header file that uses that struct. Is there any way of doing that?. (I didn't find an answer for this, sorry if it's duplicated).
Here is a snippet:
cmd.c
#include "cmd.h"
#include "params.h" //This allows usage of struct testPars
void move_parameters(struct testPars *testP) {
...
}
cmd.h
#ifndef CMD_H
#define CMD_H
#include "params.h" //I want to avoid this include in this file
void move_parameters(struct testPars *testP) ;
#endif
params.h
#ifndef PARAMS_H
#define PARAMS_H
struct testPars {
char name[16];
double value;
};
#endif
Overall, there's a lot of confusion about proper program design here.
I'm trying to keep all the struct declarations in the relevant .h files. This allows me to use them in any of the .c files by including the relevant header.
This is acceptable practice for quick & dirty programming where you have no private encapsulation, or if the structs are of a simple nature.
But for professional programs where the structs represent more complex ADTs etc, you should only keep a forward declaration in the header files, and define the struct inside the corresponding c file. This leads to private encapsulation and modularisation, i.e. good program design. (Search for examples of "opaque type" or "opaque pointers". The formal term for such forward declarations is incomplete type.)
What you are trying to do sounds like the above but completely backwards: expose the definition to the caller, but don't use it yourself. And obviously you can't use a struct that you haven't included and made visible to your program, because that doesn't make any sense.
I'm also avoiding the inclusion of header files of my project in other header files. I guess this will make the code easier to read and maintain.
This is a bad idea. Each of your header files is to be regarded as the public documentation of what the corresponding c file does and how it should be used. While the c file can be regarded as private data, the content is nothing that the caller should concern themselves with.
An important part of that header file documentation is to list all dependencies that this module has, so that other programmers can quickly take a glance at the top of your header file and immediately tell which files that are needed in order to compile this particular module.
Good program design strives for as few dependencies as possible: "loose coupling". Therefore all #includes are regarded as important information that should be put on top of the header file. Header files that aren't used should not be included.
The c file should not contain any includes except its own header file.
I found some source code that I want to incorporate into a C program I am writing. Let's call it existing.c. This file contains a typedef for a struct that is required for a parameter to a function defined lower down in the file. I want to call this function in my file main.c. I know I could probably get access to the function by declaring a function prototype in main.c, but I will also need access to that struct definition to declare and call the function.
There is no .h file for existing.c, although I could of course make one, say existing.h. But if I put the typedef in existing.h, then it seems like I would have to put #include "existing.h" into existing.c, which does not seem correct from my understanding of header files. I thought their purpose was to make the code in a certain file available to other compilation units, and shouldn't be required by that file itself.
So I guess my main question is straightforward, how do I use the function defined in existing.c in my own file main.c? Can I do it without a header file, like by putting some kind of struct prototype in main.c, similar to a function prototype, or specify the struct as external or something along those lines?
Edit: I probably should have mentioned in my original post that one reason I was hoping to avoid using a header was so I could incorporate the existing.c file unaltered in case there are revisions of this source in the future. Judging from the answers this is not possible.
if I put the typedef in existing.h, then it seems like I would have to put #include "existing.h" into existing.c, which does not seem correct from my knowledge of header files.
That is precisely the thing to do: move the typedef into the existing.h header, then include that header in both the existing.c and in your code.
I thought their purpose was to make the code in a certain file available to other compilation units, and shouldn't be required by that file itself.
That is how the headers do their job - you include them both from the implementation file and from the code that uses that implementation.
Although it is possible to write a header that matches what was in the implementation, and use it without inclusion in the implementation file itself, this is not desirable: one reason why you include the header in the implementation is to let the compiler check the code against the function prototypes from the header, and produce errors for any discrepancies it may find.
then it seems like I would have to put #include "existing.h" into existing.c, which does not seem correct
That's the proper and correct way to do it.
You place declarations in a header file if more than one compilation unit needs those declarations, and the source code file containing the implementation is almost always one of the files you include the header file in.
As per checkpatch.pl script "extern declaration be outside .c file"
(used to examine if a patch adheres coding style)
Note: this works perfectly fine without compilation warnings
The issue is solved by placing the extern declaration in .h file.
a.c
-----
int x;
...
b.c
----
extern int x;
==>checkpatch complains
a.h
-----
extern int x;
a.c
----
int x;
b.c
----
#include "a.h"
==> does not complain
I want to understand why this is better
My speculation.
Ideally the code is split into files so as to modularize the code (each file is a module)
The interface exported by the module is placed in the header files so that other modules (or .c files) can include them. so if any module wants to expose some variables externally, then one must add an extern declaration in a Header file corresponding to the module.
Again, having a header file corresponding to each module (.c file) seems like
to many header files to have.
It would be even better to include the a.h in the a.c file as well. That way the compiler can verify that the declaration and the definition match each other.
a.h
-----
extern int x;
a.c
----
#include "a.h" <<--- add this
int x;
b.c
----
#include "a.h"
The reason for the rule is, as you assume, that we should use the compiler to check what we are doing. It is much better with the tiny details.
If we allow extern declarations all over the place, we get in trouble if we ever want to change x to some other type. How many .c files do we have to scan to find all extern int x? Lots. And if we do, we will likely find some extern char x bugs as well. Oops!
Just having one declaration in a header file, and include it where needed, saves us a lot of trouble. In any real project, x will not be the only element in the header file anyway, so you are not saving on the file count.
I see two reasons:
If you share a variable, it's because it's not in your own file, so you want to make it clear that it's shared by adding the extern to a header file - that way, there is only one place [the include directory] to search for extern declarations.
It avoids someone making an extern declaration, and then someone else making a different (as in using different type or attributes) extern declaration for the same thing. At least if it's in a header file [that is relevant], all files use the same declaration.
If you ever decide to change the type, there are only two places to change. If you were to add a "c.c" file that also use the same variable, and then decide that int is not good enough, I need long, you'd have to modify all three places, rather than two as you'd have if there was a header file included in each of "a.c", "b.c" and "c.c".
Having a header file for your module is definitely not a bad idea. But it could of course be acceptable, depending on the circumstances to put the extern into some existing headerfile.
An alternative, that is quite often a better choice than using an extern, is to have a getter function, that fetches your variable for you. That way, the variable can be static in its own source file [no "namespace pollution", and the type of the variable is also much more well defined - the compiler can detect if you are trying to use it wrongly.
Edit: I should point out that Linux coding style is the way it is for "good" reasons, but it doesn't mean that code that isn't part of the Linux source code can't break those rules in various ways. I certainly don't write my own code using the formatting of Linux - I like extra { } around single statements, and I (nearly) always put { on a new line, in line with whatever the brace belongs to, and the } in the same column again.
One reason I always place the extern declarations in the .h is to prevent code duplication, especially if there are, or may be, more bits of code using your "a.c" code and having to access the "x". In that case all files would have to have the extern declaration.
Another reason is that the extern declaration is part of the interface of the module and as such I would keep it, together with any other interface information in the header file.
Your speculation is right: for maximal code reuse and consistency, the (public) declarations must be put into header files.
Again, having a header file corresponding to each module (.c file) seems like to many header files to have.
Then get used to it. It's a logical concept and a good practice to adapty
You have got the reason right as to why extern declarations must be placed in a header file. So, that they can be accessed across different translation units easily.
Also, it is not necessary that each .c file should have a corresponding .h file. One .h file can correspond to a decent number of .c files depending upon your module segregation design.
Again, having a header file corresponding to each module (.c file) seems like to0 many header files to have.
As you have said, the idea of a header file is simple. They contain the public interface that a module wants to export (make available) to other modules (contained in other .c files). This can include structures and types and function declarations. Now, if a module defines a variable which it wants to make available to other modules, it makes sense for it to be included with it's other public parts in the header file. This is why externs end up in th header file. They are just a part of the things that the module wants to make public. Then anyone can include this public interface by simply including the header file.
Having a .h file per .c file may seem like much, but it may be the right thing to do. But keep in mind that a module may implement its code in multiple .c files, and choose to export its aggregate public interface in a single .h file. So, it is not really a strict one to one thing. The real abstraction is that of the public interface offered by a module.
I am beginning to question the usefulness of "extern" keyword which is used to access variables/functions in other modules(in other files). Aren't we doing the same thing when we are using #include preprocessor to import a header file with variables/functions prototypes or function/variables definitions?
extern is needed because it declares that the symbol exists and is of a certain type, and does not allocate storage for it.
If you do:
int foo;
In a header file that is shared between several source files, you will get a linker error because each source would have its own copy of foo created and the linker will be unable to resolve the symbol.
Instead, if you have:
extern int foo;
In the header, it would declare a symbol that is defined elsewhere in each source file.
One (and only one) source file would contain
int foo;
which creates a single instance of foo for the linker to resolve.
No. The #include is a preprocessor command that says "put all of the text from this other file right here". So, all of the functions and variables in the included file are defined in the current file.
The #include preprocessor directive simply copy/pastes the text of the included file into the current position in the current file.
extern marks that a variable or function exists externally to this source file. This is done by the originator ("I am making this data available externally"), and by the recipient ("I am marking that there is external data I need"). A recipient with an unsatisfied extern will cause an Undefined Symbol error.
Which to use? I prefer using #include with the include guard pattern:
#ifndef HEADER_NAME_H
#define HEADER_NAME_H
<write your header code here>
#endif
This pattern allows you to cleanly separate anything you want an outsider to have access to into the header, without worrying about a double-include error. Any time I have to open a .c file to find what externs are available, the lack of a clear interface makes my soul gem crack.
There are indeed two ways of using functions/variables across translation units (a translation unit is usually a *.c/*.cc file).
One is the forward declaration:
Declare functions/variables using extern in the calling file. extern is actually optional for functions (functions are automatically extern), but not for variables.
Implement the function/variables in the implementing file.
The other is using header files:
Declare functions/variables using extern in a header file (*.h/*.hh). Still, extern is optional for functions, but not for variables. So you don't normally see extern before functions in header files.
In the calling *.c/*.cc file, #include the header, and call the function/variable as needed.
In the implementing *.c/*.cc file, #include the header, and implement the function/variable.
Google C++ style guide has some good discussions on the pros and cons of the two approaches.
Personally, I would prefer the header file approach, as it is the single place (the header file) a function signature is defined, calling and implementation all adhere to this one piece of definition. Thus, there would be no unnecessary discrepancies that might occur in the forward declaration approach.