this post was submitted on 30 Dec 2023
25 points (100.0% liked)

Programming

17528 readers
226 users here now

Welcome to the main community in programming.dev! Feel free to post anything relating to programming here!

Cross posting is strongly encouraged in the instance. If you feel your post or another person's post makes sense in another community cross post into it.

Hope you enjoy the instance!

Rules

Rules

  • Follow the programming.dev instance rules
  • Keep content related to programming in some way
  • If you're posting long videos try to add in some form of tldr for those who don't want to watch videos

Wormhole

Follow the wormhole through a path of communities [email protected]



founded 2 years ago
MODERATORS
 

I know this is probably a primitive topic for most, but I just got into coding in c++ because a simple project I am working on that uses esp8266 which can be programmed using c++. Before this I only had experiemce with python, javascript and typescript.

Now to my problem: I am trying to split my code that is getting longer into multiple files.

I already think that I understand right that each library has a header (.h) file and source (.cpp or .c in case of c) file. The first thing I already have problem with is that as you are defining your functions and classes in the header file and then implementing them in the source file you are repeating yourself with the declarations which is not something I would like. I presume that most IDEs will probably automatically help you with generating or editing the header file automatically as you change code in the source file and I guess I will need to learn to live with it.

Then there's the thing with importing. It may happen that if you create a library it also has some dependencies that it needs to include. But as far as I understand one library shouldn't be included multiple times. So from what I can see most libraries check whether a global variable with an ARBITRARY name that the library chooses itself is not defined and then if that's true it defines that variable to indicate it has been included (the name of the variable is not compketely arbitrary and usually follows LIBRARY_NAME_H but the convention cannot be really relyed on). When the library includes other library it also needs to check whether the variable of that library that is defined on its import is defined. The main file should also probably check this for every library it includes because it can't know what lins were already imported by libs it imported? Am I getting something wrong or is it sometimes ok for some libraries to be included multiple times. There's the #pragma once to handle these situations?

top 11 comments
sorted by: hot top controversial new old
[–] [email protected] 12 points 11 months ago (1 children)

You can generally rely on a header file doing its own check to prevent being included twice. If a header doesn’t do that, it’s either wrong or doing something fucky. It is merely a convention, but it’s so widespread that you really don’t need to worry about it.

You are mixing up some terms, so I want to help clarify. When you #include a header file, you aren’t importing a library. You are telling the compiler to insert the contents of that header file into your source where the #include line is. A library is something different. It is an already-compiled binary file. A library should also come with a header file to tell you what functions and classes are present in the library, but that header isn’t itself the library.

It may seem annoying to have to repeat yourself between headers and source, but it’s honestly something you get used to.

[–] [email protected] 4 points 11 months ago (3 children)

Thank you for your explanation! From what I have read '#pragma once' solves the problem with mutiple includes for most modern compilers, but it's always better to write the import guards for better compatability?

[–] [email protected] 6 points 11 months ago

You probably don't have to worry about the compatability of #pragma once so just use that. The only reasons to not use it is if it's important to only use standard compliant c for whatever reason or if you need to support some arcane compiler that doesn't support #pragma once. Realistically, neither of these are situations that you'll ever be put in and if you are you probably have much larger things that you need to worry about.

[–] [email protected] 4 points 11 months ago

There’s no downside to writing the guards afaik, but I’m more of a c programmer. It’s been a while since I did much c++, so I’m not up on modern conventions. But dealing with legacy code adhering to older conventions often comes with the territory with c and c++, so it’s something to keep in mind.

[–] HooDis 1 points 11 months ago* (last edited 11 months ago)

Header guards and #pragma once serve the same purpose, so i'd say use whichever method you want. #pragma once should exist on most modern compilers. If your compiler doesn't support that, then normal header guards.

one advantage of #pragma once is that it reduces the pollution of #defines that header guards introduce. For every header file, there would be one #define FILE_NAME. Depending on your naming convention of these defines, it may clutter up the global namespace in the long run.

Header guards, like you said, provide better compatibility. At the end of the day, use whichever you want. i use #pragma once because it's much more convenient. I hope this answers your question!

Edit: oh and of course, if the existing code base is using either one of those ways, stick to that same convention!

[–] [email protected] 11 points 11 months ago* (last edited 11 months ago)

The first thing I already have problem with [...]

For the record: headers suck. There's a good reason why most programming languages don't use them. They're like a realy primitive version of setting things to public/private in modules, where public things go in the header and private things don't. Modules are a very useful abstraction over this where you don't have to do as much mucking around.

[–] [email protected] 4 points 11 months ago* (last edited 11 months ago) (2 children)

I'm going to be that guy: don't bother with writing C++, write Rust. Reading C++ to get the gist of what's going on if you are unlucky enough to need to interface with it is definitely a valuable skill to have, but that's not that common. You're running into one of the issues that's part of the reason I quit that language. At one of my former employers, compiling took so much time because of gathering headers. A bunch of stuff would get recompiled without any header changes and it that xkcd comic of "what are you doing??" "just compiling", was my life. 15 goddamn minutes - no joke. inb4 "rust compiles slower than C++" - the initial compilation, for sure. subsequently it's pretty fast.

Rust has better IDE support, better tooling, actual dependency management, "memory management" (aka borrow checker), more legible syntax, a sane standard library, builtin documentation rendering (docstrings are a real thing), builtin testing support and even doctests (tests that run from the examples given in your docstring), ... It's a modern, memory safe language, with an ever-growing community, will get you jobs, and is IMO much more fun to write than C++.

Edit: yes, rust on the ESP8266 is possible https://github.com/esp-rs

CC BY-NC-SA 4.0

[–] [email protected] 3 points 11 months ago

Plus, if you eventually do need or want to learn C++ for some reason, I honestly think that knowing Rust first would be quite helpful.

[–] [email protected] 2 points 10 months ago (1 children)

And if you feel like quitting Rust, just read some c++ template compiler errors

[–] [email protected] 1 points 10 months ago* (last edited 10 months ago)

Or try compiling somebody else's project that's "just run ./config && make" and resolve all the errors that come up because their dependencies aren't clearly stated or clash with yours.

CC BY-NC-SA 4.0

[–] [email protected] 2 points 10 months ago

Cherno explains all this stuff better than anyone so far in my opinion. https://youtube.com/playlist?list=PLlrATfBNZ98dudnM48yfGUldqGD0S4FFb&si=4qea7pmH_nTynaJw

I would highly recommend it