dsyleixa123
Posts: 1025
Joined: Mon Jun 11, 2018 11:22 am

Re: questions to libs having a .h file and a .c file

Sat Sep 26, 2020 5:46 pm

thanks a lot, that makes it very clear to me!

now just a (perhaps last) crucial question (6):

OTOH, if I use the header file mylib.h and mylib.c,
why does the mylib.c file require the line #include "mylib.h" :?:

Code: Select all

//mylib.h
#pragma once

extern void myfunction(void);

Code: Select all

//mylib.c
#include <stdio.h>   
#include "mylib.h"  // <<<<<<<<< WHY ??

void myfunction(void) {
   printf("hello world");
}

Code: Select all

//mymainprogram.c
#include "mylib.h"

int main() {
   myfunction();
   return 0;
}
(tbh, it would be more clear to me even other way round, if the mylib.h file #included the mylib.c file because the .h file prototypes/declarations are sort of "expanded" by the explicite .c file functions

Heater
Posts: 16835
Joined: Tue Jul 17, 2012 3:02 pm

Re: questions to libs having a .h file and a .c file

Sat Sep 26, 2020 6:22 pm

dsyleixa123 wrote:
Sat Sep 26, 2020 5:46 pm
OTOH, if I use the header file mylib.h and mylib.c,
why does the mylib.c file require the line #include "mylib.h" :?:
I like to think of it like this:

I want factory A to make some bolts.
I want factory B to make some nuts.
I want those nuts and bolts to fit together when I get them.

To that end I had better write a specification that states what inner and outer diameters those nuts and bolts have. What the thread pitch is. And a bunch of other details.

So in C if I have bolts.c that will use functions in nuts.c. And they are manufactured separately (compiled) there had better be a specification somewhere that ensures the calls in bolts.c match the functions in nuts.c. Typically it is convenient to put that specification in nuts.h as a bunch of declarations.

Basically including the nuts.h file into nuts.c ensures that nuts.c implements the interfaces it says it does in the header file so that bolts.c can link and work with it correctly.

So it's just all about ensuring what is called at one end matches the calls at the other. By specifying (declaring) function names, return types, parameters and their types. Both C files need to include this specification to ensure things line up.
Memory in C++ is a leaky abstraction .

jamesh
Raspberry Pi Engineer & Forum Moderator
Raspberry Pi Engineer & Forum Moderator
Posts: 27412
Joined: Sat Jul 30, 2011 7:41 pm

Re: questions to libs having a .h file and a .c file

Sat Sep 26, 2020 6:31 pm

dsyleixa123 wrote:
Sat Sep 26, 2020 5:46 pm
thanks a lot, that makes it very clear to me!

now just a (perhaps last) crucial question (6):

OTOH, if I use the header file mylib.h and mylib.c,
why does the mylib.c file require the line #include "mylib.h" :?:

Code: Select all

//mylib.h
#pragma once

extern void myfunction(void);

Code: Select all

//mylib.c
#include <stdio.h>   
#include "mylib.h"  // <<<<<<<<< WHY ??

void myfunction(void) {
   printf("hello world");
}

Code: Select all

//mymainprogram.c
#include "mylib.h"

int main() {
   myfunction();
   return 0;
}
(tbh, it would be more clear to me even other way round, if the mylib.h file #included the mylib.c file because the .h file prototypes/declarations are sort of "expanded" by the explicite .c file functions
In this particular case, it does NOT need to be included. It doesn't tell the compiler any more information than it already knows.

But usually header files contain other information (constant defines etc) that you library code might need, i.e. the sort of information (not function prototypes) that does need to be shared by the library and the program.
Principal Software Engineer at Raspberry Pi (Trading) Ltd.
Contrary to popular belief, humorous signatures are allowed.
I've been saying "Mucho" to my Spanish friend a lot more lately. It means a lot to him.

User avatar
rpdom
Posts: 17708
Joined: Sun May 06, 2012 5:17 am
Location: Chelmsford, Essex, UK

Re: questions to libs having a .h file and a .c file

Sat Sep 26, 2020 6:35 pm

The .h file just declares the functions, like "This is how to call this thing". The .c file actually has the real things in it. including the .h file at the start of the .c file makes sure the compiler knows how to call the functions before they are defined later in the .c file. This is important if the first function calls the second. If you just had the .c file the the compiler wouldn't know about the second function at that point.
Unreadable squiggle

dsyleixa123
Posts: 1025
Joined: Mon Jun 11, 2018 11:22 am

Re: questions to libs having a .h file and a .c file

Sat Sep 26, 2020 9:18 pm

rpdom wrote:
Sat Sep 26, 2020 6:35 pm
The .h file just declares the functions, like "This is how to call this thing". The .c file actually has the real things in it. including the .h file at the start of the .c file makes sure the compiler knows how to call the functions before they are defined later in the .c file. This is important if the first function calls the second. If you just had the .c file the the compiler wouldn't know about the second function at that point.
jamesh wrote:
Sat Sep 26, 2020 6:31 pm
In this particular case, it does NOT need to be included. It doesn't tell the compiler any more information than it already knows.
But usually header files contain other information (constant defines etc) that you library code might need, i.e. the sort of information (not function prototypes) that does need to be shared by the library and the program.
Heater wrote:
Sat Sep 26, 2020 5:37 pm
Also, consider the case of libraries for which you have binary library files. Shared objects, .so, or statically linked library files, .a.
If your program wants to use those it needs to know what functions and other stuff they offer. But it does not have access to the source files of those libraries. The library header files tell what is in the library and ensure your compilation is correct.
And anyway, you don't want to be compiling those libraries by including their source. Last time I built QT 5 on a Pi it took all night!
No, we just build our programs against the library header files. Then link the library objects.
ah yes, I see, just like using function declarations at the top of a program in cases when a 1st listed function calls a 2nd function or uses other definitions listed not yet until then. That makes sense, great, thanks @all!

mlp6868
Posts: 35
Joined: Sun Sep 27, 2020 11:48 pm

Re: questions to libs having a .h file and a .c file

Fri Oct 02, 2020 4:17 am

Maybe we should slow down a bit...

dsyleixa123 states in another thread that he or she is a beginner. We in this forum should point out things that are really unusual or bad practice. They may serve to make an academic point, but people tend to dismiss that code and we should point that out. Of course people are battling over style issues when it comes to code a lot, but a few things I guess are not controversial.

So we should say that this (including a .c file in another) is really bad practice:
/mymainprogram.c
#include "mylib.c"

int main() {
myfunction();
return 0;
}
I'd say you should never include another .c file this way.

The way it was shown with a header file (mylib.h) and two source files (mylib.c and mymainprogram.c) is (for larger files at least) the way to go, especially if there is a chance that whatever mylib.c provides is useful with other programs (then it is usually made into a library, as the name already implies).

Also, no one (I may have missed it) has commented on the use of the "extern" in

Code: Select all

extern void myfunction(void);
that is not needed. I teach polemically that "extern is evil" - ok, what I want to get across is that if you need to use "extern", you'd better have a good reason to do so. In this case, the function is not "extern". It is defined right in the code we have.

In this context, let me take another stab at the explanation with header files. We want to separate the description from implementation. All we need to know is how something can be called, and our program doesn't really care at how it is done and what happens under the hood. I like to call a declaration like

Code: Select all

//mylib.h
#pragma once

void myfunction(void);
a "contract" - the header file tells the program what to expect, and my program uses that service.

Look at a version of the classic "hello world" program:

Code: Select all

#include <stdio.h>

int main()
{
  printf ("Hello, World!\n");
  return 0;
}
Ok, easy enough. Just like your mylib.h, stdio.h tells the compiler what "printf" is, how it can be called, and what it returns, if anything - the contract part. Then the compiler knows what to do, and the linker then goes and puts the call together with the printf function's implementation.

Now where does the linker find that implementation? The system provides a bunch of libraries, usually called system libraries, with this installation. A library that provides that heavily OS-dependent "printf" is referenced by the linker by default, and that's why, different from your example "mylib.c" implementation, you don't have to explicitly specify this.

Again, my "contract" paradigm - you can imagine that the specifics of actually printing "Hello, World" to your screen (going through the formatting, then talking to your window manager, your graphics card, and on and on, to make those letters appear on the screen) is highly system- and hardware dependent (and also differs between a Linux system, a Mac, a Windows system). Yet by just exercising that service, described by the contract, yields the same result across different hardware, OS flavours, and so on.

Does this make sense? Hope it helps.

- mlp

dsyleixa123
Posts: 1025
Joined: Mon Jun 11, 2018 11:22 am

Re: questions to libs having a .h file and a .c file

Fri Oct 02, 2020 7:59 am

thanks for your contribution!
I appreciate your advices about what is a good and what is a bad practice, but the crucial question is: WHY is that so, which are the pros and cons and pitfalls for either one?
JTM, the "extern" thing comes from another thread where C libs also are optionally compiled by g++ for C++ projects, (e.g., like wiringPi)
and the #include "mylib.c" was just for simple cases when I just have very few functions to publish.
Tbh, I currently do not see yet why to refrain from one or the other.

Heater
Posts: 16835
Joined: Tue Jul 17, 2012 3:02 pm

Re: questions to libs having a .h file and a .c file

Fri Oct 02, 2020 9:03 am

dsyleixa123 wrote:
Fri Oct 02, 2020 7:59 am
thanks for your contribution!
WHY is that so, which are the pros and cons and pitfalls for either one?
JTM, the "extern" thing comes from another thread where C libs ....
I'll tackle that "extern" thing:

When you write something like

Code: Select all

extern void myfunction(void);
Then quite likely you will be able to compile that particular C file. Not into a runnable program of course because you don't actually have a "myfuncion()" in your code, it''s external someplace. But you could compile it to an object file, .o.

Now imagine I give you another file C containing that myfuction(). Great now you can compile both and link them together to make an executable.

BUT. What if the "myfunction" I wrote for you has a return value? What if it expects a parameter or two? Or what if you even had that in your extern al the parameter/return types were different?

Oop. You program fails to build. Both the C files will compile separately but the linker will fail to create an executable because the types are different. You are pissed of with me for supplying an incorrect "myfunction". Or I think you are an idiot because you have used "myfunction" incorrectly.

What to do? Better would be if you did not use that "extern". Better if I had a header file with my function declaration in it. I give you that and you write your code. Which compiles as before. I also use that same header file when writing "myfunction()". Which also compiles. But now we can be sure that the myfunction I write matches the one that you call. You can build an executable We are both happy. You are not an idiot. :)

This description is about you and me writing different parts of a big project in multiple C files and being sure they will link together. It's even more effective if there is more people contributing code to the project. It's even convenient for you if you are writing dozens of files for yourself.

In short, having declarations in headers allows the compiler to check everything is OK to link together. Rather than you having to manage hundreds of "externs" splattered all over your code. It means code can be developed even when the functions it wants to use don't exist and that when they are written that header is the reference that ensures the new functions are written with the correct type signatures.

All this was described in my reply here days ago: viewtopic.php?f=33&t=286347&p=1736030#p1732924

Note: Of course for every "bad practice", like using externs, there is sometimes a very good reason to use them. For example: What if the function referred to is not even written in C? Perhaps it is written in assembler or Rust or Pascal. Then it will not have a C header file supplied with it. Perhaps then, if you were just using one such "foreign function" from one C file you might not bother creating a header file for it's declaration. Just "extern" it.
Memory in C++ is a leaky abstraction .

dsyleixa123
Posts: 1025
Joined: Mon Jun 11, 2018 11:22 am

Re: questions to libs having a .h file and a .c file

Fri Oct 02, 2020 9:11 am

tbh, as to "extern" I do not quite see your point...
what different things would happen if the myfunction() was declared the other way in the .h header file

Code: Select all

#ifdef __cplusplus
extern "C" {
#endif
extern void myfunction(void) ;
#ifdef __cplusplus
}
#endif
in that case for ISO C finally also (just) the line
extern void myfunction(void) ;
would be left for compile + build


OTOH, as to the simplified #include "mylib.c" example, without any header file, of course I had not used that "extern" at all, as stated:

Code: Select all

// mylib.c
void myfunction(void) {
   printf("hello world");
}

Code: Select all

 
//mymainprogram.c
#include "mylib.c"

int main() {
   myfunction();
   return 0;
}

(JTM, I always am compiling my proprietary programs by g++, anyway if it's C or C++ code or mixed, but of course that's only for my personal convenience reasons)

Heater
Posts: 16835
Joined: Tue Jul 17, 2012 3:02 pm

Re: questions to libs having a .h file and a .c file

Fri Oct 02, 2020 11:11 am

Let's for get that 'extern "C" {...' thing for a minute.

What I wrote above is about plain old 'extern' on function declarations and variables in C (or C++) source files.

If you write:
```
void myfunction();
```
That is a "forward declaration" it tells the compiler that there is such a function defined further down your source file. Other functions that come before that definition can call 'myfunction()' because that forward declaration tells the compiler what it will look like when it gets down to the actual definition in the file.

Adding 'extern' to that declaration says 'myfunction()' will not be found in the current C file. It is in some external file that will be linked into the program later.

Typically it is desirable to put declarations into header files (without the "extern") so that both the C file containing the caller and the C file containing the definition are sure to be using the same function signatures or variable type.

As I explained above. Do say if that is not clear.

The ''extern "C" {' thing is only for C++ files that want to use things defined in C. In this case not only are they external to the C++ file that is using them but the names that C++ uses internally for function names in the object files need to be standard C style, not so called "mangled" names.

See "Name Mangling" https://en.wikipedia.org/wiki/Name_mangling
I always am compiling my proprietary programs by g++, anyway if it's C or C++ code or mixed, but of course that's only for my personal convenience reasons
That is OK. But be aware that g++ compiles files as if they were C++ files. Which means:

1) Some valid C syntax will not be accepted. C++ and C are no longer totally compatible that way.

2) g++ will do that name mangling on function names in the object files.

Of course if you compile your "C" code using g++ then you are producing a C++ object file with mangled function names. In which case there is no need to use 'extern "C" {'. You are no longer actually linking against C.
Memory in C++ is a leaky abstraction .

dsyleixa123
Posts: 1025
Joined: Mon Jun 11, 2018 11:22 am

Re: questions to libs having a .h file and a .c file

Fri Oct 02, 2020 11:33 am

I still don't understand your point.
as for the #ifdef __cplusplus version then the "extern" statement would be kept even for gcc,
so why would it fail for plain C if it stands as "extern" from the start?

As to the other things about C++ mangling and object files and being compiled or linked to whatever that doesn't interest me so much ftm and I don't understand the relevance, the libs simply have to work. If valid C syntax wasn't accepted then I'd improve it to mutual compatibility (e.g., like the (void) parameter), and I also don't use different entities named with the same identifier. Nonetheless, in case of conflicts I will use the wrapper though
#ifdef __cplusplus
extern "C" {
#endif
extern [functionname] ;
#ifdef __cplusplus
}
#endif

So the question is just about
- why the "extern" thing in a .h file should always be averted for plain C as mentioned by you and mlp6868,
- why things like #include "mylib.c" without a .h file should always be averted, apart from cross-over function calls (jtm, that I could even make the fwd declarations also just in the .c file if necessary).

Heater
Posts: 16835
Joined: Tue Jul 17, 2012 3:02 pm

Re: questions to libs having a .h file and a .c file

Fri Oct 02, 2020 1:46 pm

dsyleixa123 wrote:
Fri Oct 02, 2020 11:33 am
I still don't understand your point.
The point is I'm trying to answer your questions, which have included:

* Why we even have header files.
* Why using extern in C source files is not generally good practice.
* What all that extern "C" stuff is about.

I tried to make it as clear as possible.
dsyleixa123 wrote:
Fri Oct 02, 2020 11:33 am
...as for the #ifdef __cplusplus version then the "extern" statement would be kept even for gcc,
so why would it fail for plain C if it stands as "extern" from the start?
Let's not confuse things by talking about GCC/gcc.

If you "gcc" is a front end. I will compile you source files as C or C++ depending on the file name extension, .c vs .cpp and others. Or you can specify the source type with a command line option to gcc. See the gcc manual: https://linux.die.net/man/1/gcc
dsyleixa123 wrote:
Fri Oct 02, 2020 11:33 am
As to the other things about C++ mangling and object files and being compiled or linked to whatever that doesn't interest me so much ftm and I don't understand the relevance, the libs simply have to work.
The relevance is that you have been asking about "extern "C"". Apparently you have or had it in your code. Try not to be so contrary and confusing.
dsyleixa123 wrote:
Fri Oct 02, 2020 11:33 am
If valid C syntax wasn't accepted then I'd improve it to mutual compatibility (e.g., like the (void) parameter),
That is likely a good idea. Just change the file name extension to .cpp and compile it with gcc or g++, as a C++ source file. Then at least you won't need "extern "C"" anymore because everything you do is now C++ source.
dsyleixa123 wrote:
Fri Oct 02, 2020 11:33 am
... and I also don't use different entities named with the same identifier...
That is a good idea.

Of course you can do that in C++ if you put the entities in different name spaces: https://en.cppreference.com/w/cpp/language/namespace.

and you are likely to have methods with the same names in different classes.
dsyleixa123 wrote:
Fri Oct 02, 2020 11:33 am
Nonetheless, in case of conflicts I will use the wrapper though
#ifdef __cplusplus
extern "C" {
#endif
extern [functionname] ;
#ifdef __cplusplus
}
#endif
Let's forget about that "extern "C"" thing shall we? After all you are not using C and apparently you don't need to link against and C or anything that uses a C linking convention. So you don't need it anywhere.
dsyleixa123 wrote:
Fri Oct 02, 2020 11:33 am
So the question is just about
- why the "extern" thing in a .h file should always be averted for plain C as mentioned by you and mlp6868,
We did not say use "extern" in header files. In fact we specifically said not to. You don't need "extern" if you organize you function/variable declarations, constant definitions, etc, into header files as we suggested a couple of times now at least.
dsyleixa123 wrote:
Fri Oct 02, 2020 11:33 am
- why things like #include "mylib.c" without a .h file should always be averted, apart from cross-over function calls (jtm, that I could even make the fwd declarations also just in the .c file if necessary).
Please, read what we posted above again. It is all explained there. Multiple times in different ways. Start with my analogy to making nuts and bolts and the necessity for a specification here: viewtopic.php?f=33&t=286347&p=1736157#p1732924
Memory in C++ is a leaky abstraction .

dsyleixa123
Posts: 1025
Joined: Mon Jun 11, 2018 11:22 am

Re: questions to libs having a .h file and a .c file

Fri Oct 02, 2020 2:09 pm

no sorry, you didn't answer my questions, at least not clearly enough so that I could understand it.
Until viewtopic.php?p=1733021#p1733021 all was quite clear, but then mlp6868 mixed it up.

I see some advantages of doing this or that in some cases or not, but no "MUST" to do it either way, and no reasons for "really bad practice".

jtm: I never rename *.c to *.cpp, I call any C/C++ source of either content just *.c

And I never compile .c files to single .o files or whatever but just the whole thing in 1 line like
gcc/g++ -Wall -o myfile myfile.c -lwiringPi -lpthread
(actually it's a line in Geany build preferences: gcc/g++ -Wall -o "%e" "%f" -lwiringPi -lpthread )

Now the open questions:

you or mlp6868 said: really bad practice to use extern [functionname] in a header file:
why? what will it corrupt?

mlp6868 said: really bad practice to use #include "mylib.c" in a program source file (i.e.,without an extra header file):
why? (crossover function calls are no issue here)

(BTW: by "it should be averted" I meant: "don't use it")

please answer in short sentences with simple words, I am not a native English speaker.

Heater
Posts: 16835
Joined: Tue Jul 17, 2012 3:02 pm

Re: questions to libs having a .h file and a .c file

Fri Oct 02, 2020 5:49 pm

dsyleixa123 wrote:
Fri Oct 02, 2020 2:09 pm
I see some advantages of doing this or that in some cases or not, but no "MUST" to do it either way, and no reasons for "really bad practice".
I would not go as far to say anything is "really bad practice" in your little one man projects. Nobody but you cares what gets written in there. If it works, it works, all is good, right?

However, if you ever work with other people. Or if you are using code from other people. Or if you are making code available to other people. It will be greatly appreciated if you do not do weir, daft, unnecessary things that cause confusion.
dsyleixa123 wrote:
Fri Oct 02, 2020 2:09 pm
jtm: I never rename *.c to *.cpp, I call any C/C++ source of either content just *.c
I have no idea what "jtm" means. But that is just daft. File name extensions are almost universally used to indicate the type of content of the files. They are used to distinguish the programing language that source files contain. The C language is not C++ so it's daft to call them all "*.c".

This is an example of a weird thing that would cause confusion and cause other people working with you or your code to think you are an idiot. We would not want that now, would we?

Again though, in your own little isolated world, working by yourself it is not a "bad" thing. Nobody cares. It will not cause your programs to crash, or your cat to leave home, or you house to burn down.
dsyleixa123 wrote:
Fri Oct 02, 2020 2:09 pm
And I never compile .c files to single .o files or whatever but just the whole thing in 1 line like
gcc/g++ -Wall -o myfile myfile.c -lwiringPi -lpthread
(actually it's a line in Geany build preferences: gcc/g++ -Wall -o "%e" "%f" -lwiringPi -lpthread )
Never I have I seen "gcc/g++". Is that actually, literally,, what you write in there?

I don't even see how a C++ file can be compiled as a C file. Given that it has a .c extension as you say, and hence get compiled as C not C++.

you or mlp6868 said: really bad practice to use extern [functionname] in a header file:
why? what will it corrupt?
dsyleixa123 wrote:
Fri Oct 02, 2020 2:09 pm
mlp6868 said: really bad practice to use #include "mylib.c" in a program source file (i.e.,without an extra header file):
why? (crossover function calls are no issue here)
Please see the explanations above.

Again, nothing bad will happen if you do that in your own little project. It might confuse others if you find yourself working with them. It might confuse yourself one day when you are trying to build hundreds of files into a bigger project. At which time you might remember what we said and see why we said it.
Memory in C++ is a leaky abstraction .

dsyleixa123
Posts: 1025
Joined: Mon Jun 11, 2018 11:22 am

Re: questions to libs having a .h file and a .c file

Fri Oct 02, 2020 6:06 pm

by
gcc/g++ -Wall -o myfile myfile.c -lwiringPi -lpthread
I mean either
gcc -Wall -o myfile myfile.c -lwiringPi -lpthread
or optionally
g++ -Wall -o myfile myfile.c -lwiringPi -lpthread
just depending on what I want to use

jtm= just to mention ;)

but now what you wrote makes it clearer to me, that it's just not common, but will work.

Nonetheless,
it also works if I write a file with C++ cmds e.g. using <iostream> and std::cout and call it myfile.c and compile by g++

Code: Select all

// iostreamtest.c

#include <iostream>
#include <stdio.h>

int main() {  
   std::cout << "Hello World!";
   getchar();
   return 0;
}
(runs like a charm)

and #including a couple of .c files IMO makes it not more complicated than #including .h files

Code: Select all

// cfilelibtest.c

#include "mylib1.c"  // feat myfunc1()
#include "mylib2.c"  // feat myfunc2()
#include "mylib3.c"  // feat myfunc3()

int main() {  
   myfunc1();
   myfunc2();
   myfunc3(); 
   return 0;
}
(runs like a charm)

So good to know that it wouldn't break or corrupt anything, finally.
I'm curious that anyone might call me an idiot because of that, though.
But thank you very much!

Heater
Posts: 16835
Joined: Tue Jul 17, 2012 3:02 pm

Re: questions to libs having a .h file and a .c file

Fri Oct 02, 2020 6:55 pm

Excellent.
dsyleixa123 wrote:
Fri Oct 02, 2020 6:06 pm
I'm curious that anyone might call me an idiot because of that, though.
In my experience of programmers I have worked with over many years, or open source developers, they might likely have much worse things to call people who make a mess in a project.

Similarly in other lines of work.
dsyleixa123 wrote:
Fri Oct 02, 2020 6:06 pm
But thank you very much!
No worries. Glad to be of service.
Memory in C++ is a leaky abstraction .

mlp6868
Posts: 35
Joined: Sun Sep 27, 2020 11:48 pm

Re: questions to libs having a .h file and a .c file

Sat Oct 03, 2020 4:54 am

I'll give this one last shot...

You are asking why (and I argued this strongly) this is bad, when it seems to work. Indeed, you have made up a simple example where it does work:

Code: Select all

// cfilelibtest.c

#include "mylib1.c"  // feat myfunc1()
#include "mylib2.c"  // feat myfunc2()
#include "mylib3.c"  // feat myfunc3()

int main() {  
   myfunc1();
   myfunc2();
   myfunc3(); 
   return 0;
}
So good to know that it wouldn't break or corrupt anything, finally.
I'm curious that anyone might call me an idiot because of that, though.
We are not calling you an idiot. We are not saying that it doesn't work in certain instances. What we are trying to point out is that this is bad code, even if you can get it to work in this particular instance. It is still bad practice, and not the way it's done.

Look, in another thread here you state that you are a beginner learning C/C++ in order to find a different line of work. We are trying to warn you that you will not survive the first 5 minutes of a job interview when you are asked to show some example code and you show this. This would certainly be true in the place where I work.

If you pretend to be a handyman, and then you use a large screwdriver to pound a nail into the wall, it may work, but it still isn't the right way to go about it. We are trying to help you out, but we cannot really re-hash 30 years of "best practice" code development guidance that you can read up on in many places.

I have tried to make up an example where you need header files, although even here it it might be possible to somehow make the "screwdriver to hammer a nail" approach work with some more bad code.

Here I have 3 source and two header files, and threw in a README (to say how to compile this)

Code: Select all

func_A.c
func_A.h
func_B.c
func_B.h
mainprog.c
README
func_A.c looks like

Code: Select all

#include "func_A.h"
#include "func_B.h"

#include <stdio.h>

int func_A(const int i)
{
  if ( i > 3) return i;
  printf("in func_A, par = %d\n",i);
  return func_B(i+1);
}
you see, it calls func_B, and func_B.c is

Code: Select all

#include "func_B.h"
#include "func_A.h"

#include <stdio.h>

int func_B(const int i)
{
  if ( i > 3) return i;
  printf("in func_B, par = %d\n",i);
  return func_A(i+1);
}
and calls func_A. So the functions cross-call each other; they have an end condition so this ends at some point.
Ok so far? They have their header files, func_A.h

Code: Select all

#ifndef __FUNC_A__
#define __FUNC_A__

int func_A(const int i);

#endif
and the func_B.h in the same spirit, and the mainprog.c:

Code: Select all

#include "func_A.h"

int main()
{
  int i;
  i = func_A(0);
  return 0;
}
compile and run:

Code: Select all

$ gcc -o mainprog mainprog.c func_A.c func_B.c
$ ./mainprog
in func_A, par = 0
in func_B, par = 1
in func_A, par = 2
in func_B, par = 3
works as it should.

Now I made a "clone" of this where I eliminated all header files, just 3 .c files and again a README:

Code: Select all

func_A.c
func_B.c
mainprog.c
README
where mainprog.c now includes the .c files:

Code: Select all

#include "func_A.c"
#include "func_B.c"

int main()
{
  int i;
  i = func_A(0);
  return 0;
}
This does not compile:

Code: Select all

$ gcc -o mainprog mainprog.c
In file included from mainprog.c:1:
func_A.c: In function ‘func_A’:
func_A.c:8:10: warning: implicit declaration of function ‘func_B’; did you mean ‘func_A’? [-Wimplicit-function-declaration]
   return func_B(i+1);
          ^~~~~~
          func_A
 
I have attached the source tree. Try it.

I really hope it helps. Good luck!

- mlp
Attachments
right_and_wrong.tar.gz
(866 Bytes) Downloaded 7 times

User avatar
jahboater
Posts: 6281
Joined: Wed Feb 04, 2015 6:38 pm
Location: Wonderful West Dorset

Re: questions to libs having a .h file and a .c file

Sat Oct 03, 2020 7:28 am

Just avoid putting code in header files.
Pi4 8GB running PIOS64 Lite

Heater
Posts: 16835
Joined: Tue Jul 17, 2012 3:02 pm

Re: questions to libs having a .h file and a .c file

Sat Oct 03, 2020 8:57 am

jahboater wrote:
Sat Oct 03, 2020 7:28 am
Just avoid putting code in header files.
Oh boy...

Thing is "header only libraries" are a big thing that many people do on purpose. Especially in the C++ world.

The Top 137 Header Only Open Source Projects: https://awesomeopensource.com/projects/header-only
And: https://subscription.packtpub.com/book/ ... -libraries

Personally I think it's nuts. The whole .c source and .h header file thing is clunky and daft.

For many decades I have wished we did not have it. We should just be able to write something at the top of our program files that effectively says "Use this code from over there". Where "over there" now a days could be a repository on Github or whatever. The compiler/build system should then just sort it out with out expecting me to faff around with header files and such tedious book keeping trivia.

Of course I had never formulated a clear idea of what I wanted back then. It turns out the notion of "modules" is what I was after.

It also turns out the C++ guys have also been wanting to fix this for decades. And we now have modules in C++ 2020: https://docs.microsoft.com/en-us/cpp/cp ... ew=vs-2019

Hurray! One will eventually be able to program without dicking around with header files.

Luckily Rust has always had modules. I'm happy already :)
Memory in C++ is a leaky abstraction .

dsyleixa123
Posts: 1025
Joined: Mon Jun 11, 2018 11:22 am

Re: questions to libs having a .h file and a .c file

Sat Oct 03, 2020 9:15 am

thanks, I understand that for cross-over-calls of library functions header files are meaningful, and for general purposes and for compatibility reasons they make sense for being #included.

PS,
"header only libraries" or actually, "c-file only libraries" was actually also what I had in my mind, not always having to deal which both .h and .c files, but it's ok, finally it's all not so extremely overcomplicated

enedil
Posts: 80
Joined: Sat Feb 21, 2015 4:22 pm
Location: Toruń, Poland
Contact: Website

Re: questions to libs having a .h file and a .c file

Tue Oct 13, 2020 4:11 pm

Heater wrote:
Sat Oct 03, 2020 8:57 am
jahboater wrote:
Sat Oct 03, 2020 7:28 am
Just avoid putting code in header files.
Oh boy...

Thing is "header only libraries" are a big thing that many people do on purpose. Especially in the C++ world.

The Top 137 Header Only Open Source Projects: https://awesomeopensource.com/projects/header-only
And: https://subscription.packtpub.com/book/ ... -libraries

Personally I think it's nuts. The whole .c source and .h header file thing is clunky and daft.
I'm not advocating header-only libraries, but there are valid usecases, like templates (used widely in STL).
- What Can a Thoughtful Man Hope for Mankind on Earth, Given the Experience of the Past Million Years?
- Nothing.

Kurt Vonnegut, Cat's Cradle

enedil
Posts: 80
Joined: Sat Feb 21, 2015 4:22 pm
Location: Toruń, Poland
Contact: Website

Re: questions to libs having a .h file and a .c file

Tue Oct 13, 2020 4:20 pm

Also, out of other reasons of not including .c files, if you're building a bigger project, you'll start noticing that build times get longer and longer. Split that into separate source files, use GNU make (or cmake or ninja or bazel, whatever you like) to compile your project. What will happen is that only the modified source files will be recompiled, and everything will be relinked. This reduces build times considerably. Even in the case of single compilation, separation into .c files gives time-compile benefits, since even GNU make can utilize multiple CPU cores (-j flag), but only if there are multiple object files to be compiled.
Alas, there are some inconveniences to this approach. For instance, I read that if your code is in single compilation unit, GCC can optimize your code better by 10-15% (CITATION NEEDED, but still conceivable).
- What Can a Thoughtful Man Hope for Mankind on Earth, Given the Experience of the Past Million Years?
- Nothing.

Kurt Vonnegut, Cat's Cradle

User avatar
jahboater
Posts: 6281
Joined: Wed Feb 04, 2015 6:38 pm
Location: Wonderful West Dorset

Re: questions to libs having a .h file and a .c file

Tue Oct 13, 2020 5:13 pm

enedil wrote:
Tue Oct 13, 2020 4:20 pm
Alas, there are some inconveniences to this approach. For instance, I read that if your code is in single compilation unit, GCC can optimize your code better by 10-15% (CITATION NEEDED, but still conceivable).
Do you mean this?

Code: Select all

-fwhole-program
   Assume that the current compilation unit represents the whole program being compiled.
   All public functions and variables with the exception of "main" and those merged by
   attribute "externally_visible" become static functions and in effect are optimized
   more aggressively by interprocedural optimizers.
Pi4 8GB running PIOS64 Lite

enedil
Posts: 80
Joined: Sat Feb 21, 2015 4:22 pm
Location: Toruń, Poland
Contact: Website

Re: questions to libs having a .h file and a .c file

Tue Oct 13, 2020 5:31 pm

jahboater wrote:
Tue Oct 13, 2020 5:13 pm
enedil wrote:
Tue Oct 13, 2020 4:20 pm
Alas, there are some inconveniences to this approach. For instance, I read that if your code is in single compilation unit, GCC can optimize your code better by 10-15% (CITATION NEEDED, but still conceivable).
Do you mean this?

Code: Select all

-fwhole-program
   Assume that the current compilation unit represents the whole program being compiled.
   All public functions and variables with the exception of "main" and those merged by
   attribute "externally_visible" become static functions and in effect are optimized
   more aggressively by interprocedural optimizers.
Yes, and as far as I understand, one needs to put whole code in one file (or include source files).
- What Can a Thoughtful Man Hope for Mankind on Earth, Given the Experience of the Past Million Years?
- Nothing.

Kurt Vonnegut, Cat's Cradle

Return to “C/C++”