I have a large static const byte array that I will be hard defining. This ends up with about 500 lines of wall-of-text type code that is a bit of an eyesore among the rest of the normal flow of the file. In addition, the byte contents of the file is something that would likely be generated by a script type parser.
static const uint8_t largeArray[0x4000]
{
// About 500 lines of content here.
}
In this situation, is it acceptable style to simply create another .c file and then simply include it in my original source file in order to make the 500 lines turn into one? In general I despise including .c in another .c but I'm not sure what the recommended practice is for situations like this.
static const uint8_t largeArray[0x4000]
{
#include "ArrayContents.c" // One line, but not nice file structure.
}
It is acceptable and may typically happen where the large array is generated by some other process, but typically you would want to give the file a different suffix, like .hc instead of .c so that people are not confused about that it is neither a header file or a source file in its own.
An alternative is to just have the content of the file in a different .c file, with just;
const uint8_t largeArray[0x4000]
{
// About 500 lines of content here.
}
and then just declare it an extern in the file where you are using it, e.g.;
extern const uint8_t largeArray[0x4000];
Related
I am aware there are multiple questions regarding this problem but none provides a solution under my constraints.
I am working on a project where a header file mips_cpu.h with a certain API is given. I am intended to develope its implementation without altering the header file. This API includes a structure declared in a file mips_cpu.cpp as:
struct mips_cpu_impl;
typedef struct mips_cpu_impl *mips_cpu_h;
I have then defined this structure in mips_cpu.cpp as:
struct mips_cpu_impl{
//Program Counter
uint32_t pc;
uint32_t pcN;
//General Purpose Registers
uint32_t GPReg[32];
//Special registers for MUL / DIV instructions
uint32_t LO;
uint32_t HI;
----- more code ---
};
The problem comes when using this structure in another file mips_cpu_instruction.cpp. When I have this code:
mips_error ADDI(mips_cpu_h state, uint8_t rs, uint8_t rt, uint16_t imm){
uint64_t check = state->GPReg[rs] + imm;
uint32_t tmp = state->GPReg[rs] + imm;
...
more code and appropriate return
}
state then gives the error: use of undefined type 'mips_cpu_imps'
Including the declaration of the structure in the header file solves the problem but I am not supposed to change the header files. Also the header files contain guards, which I dont fullly understand but might be relevant?
The problem is that the file mips_cpu_instruction.cpp doesn't know anything about struct mips_cpu_imps, because it probably includes the .h file that you can't touch (mips_cpu.h), but certainly not the .cpp file where that struct is defined (mips_cpu.cpp). You can add the declaration to mips_cpu_instruction.cpp, but then you'd have a problem if there were other files in the project that use this struct, because you'd have to define it there as well, and when linking you'd get multiple declarations of the same struct.
The best solution would be to add it to the file that you can't modify, but since you can't modify it, you need a workaround. I would create another .h file, using include guards to protect the code from multiple inclusion, and then I would safely #include this new .h file at the top of every .cpp file that needs it. Then it would be defined everywhere, and just once.
In the end, this would mean that to use these APIs you'd have to include 2 .h files: the one you can't touch, and the new one. If you don't want to include 2 files every time, you could even decide to #include mips_cpu.h inside your new file, and then you'd just have to #include the new one, and you could pretty much forget about your unmodifiable file.
Your structure isn't fully defined. It's defined enough for people to use the functions, but not enough to implement the functions. I suspect this is homework and your assignment is to implement these functions, including this structure.
To allow you to get past the programming issue without helping you do your homework directly, put:
struct mips_cpu_impl
{
unsigned GPReg[1];
};
at the top of your mips_cpu_instruction.cpp file, and you'll see these compiler errors go away. You'll need to properly size the array and add whatever other state things you need to model the MIPS core.
p.s. TAs exist for a reason.
In my C project, I am reading data from an obj file and an image file for opengl. All the data is combined into 1 header file.
Example (psuedo code):
vertices = {
0 , 2, 4,
....
};
normals = {
0, 0, 0,
....
};
texture_pixels = {
0, 0, 0
...
}
The thing is that all this data adds up to a 15mb header. Is it a bad idea to have this massive header? Will this cause any issues in my program?
Whether having a big header file vs. other approaches depends on the application.
The header file is processed at compile time. If the file is infrequently compiled, or its compilation time is quick enough to be acceptable, there is no problem.
If the header file is frequently updated (say like more than once per day) even in its deployed configuration, perhaps the program could be rearchitected to read the equivalent data from a data file from the network, SD card, disk, or what-have-you.
Data files have their own weaknesses:
They are a separate piece apart from the program executable which may need to be kept in sync.
The file format is subject to big vs. little endian issues, unless it is coded in some character format (like XML).
How should the program find the data? Command line parameter, hard coded path, etc.
If the file cannot be found, what to do?
Usually you declare types and function prototypes in headers. and the only function bodies should be inline functions or static functions.
Header files are combined in the source during pre-processing. it is means the large header file will be combined to any source file who is including it.
it is not the right thing to declare variables in a header files. if you declare variable in the headers and include it from several source file, you'll get the "already defined" link error, exactly as if you declare 2 global variables with the same name.
if the header file is included only once than it is exactly like to put it in the source file.
but in any other case the large data should be located in a source file, and the header should contain only the extern declaration of the variables.
The compilation time for a source file depends it size after pre-processing. therefore if you reduce the file size by exporting parts to headers you won't improve the compilation time. if you divide it to several source files any part will be compiled separately, it slow down the compilation by a bit, but when you change one part, other parts won't be needed to recompile so sometimes it is better.
In my folder I have a small version.cpp file with the following structure:
#include "thelibr/version.h"
const int major = MAJOR;
const int minor = MINOR;
I cannot understand what this code does and how is it used by the remaining part of the code (stored in other files of the same directory).
First, I understand that the code sets values of two variables (major and minor) but what is not clear to me is where the values of MAJOR and MINOR are set. Are they set in thelibr/version.h.
Second, it is also not clear to me when the above given lines of the code are executed. They are not put in any method that could potentially be called from other methods coded in other files. So, how these lines can be called?
Third, I see that string version is not present in any other file from the same directory. Does it mean that none of these file uses the code stored in the version.cpp. Shouldn't we include version.h file somewhere in other file to be able to use the code from the version.cpp?
Fourth, if we set the values of major and minor variables in the version.cpp, will these variables be visible somewhere else? It wonders me since we do not use any words like global or external.
C++ doesn't have a module system like Python where pure symbols may be exported and their values used in another source file. Instead it has header files: The contents of thelibr/version.h are essentially copy-pasted in place of the #include line. Anything inside that file is processed as if it were written out in the version.cpp file.
To export from one file to another (or to create libraries which can be interpreted by the linker or dynamic loader), use extern storage, which is the default for many things.
Deciding what is visible from one .cpp file to the next is rather complicated, but as a rule you cannot share compile-time values such as the version number; you can only share access to runtime objects such as the ints which store the version number.
To use major and minor from another .cpp file, you could declare in version.h:
extern const int major;
extern const int minor;
And then #include "thelibr/version.h" from the other file.
I've coded an script that generates a header file with constants like version, svn tag, build number. Then, I have a class that creates a string with this information.
My problem is the following: As the file is created in every compilation, the compiler detects that the header has changed, and forces the recompilation of a large number of files. I guess that the problem is in the situation of the header file. My project is a library and header has to be in the "interface to the world" header file (it must to be public).
I need some advice to minimize this compilation time or to reduce the files forced to recompile.
In the header write something like:
extern const char *VERSION;
extern const char *TAG;
extern const char *BUILD_DATE;
and create a .c (or .cpp) file that will contain
const char *VERSION = "0.13";
const char *TAG = "v_0_13";
const char *BUILD_DATE = "2011-02-02 11:19 UTC+0100";
If your script updates the .c file, only that file will have to be recompiled, but the files that include your header won't.
Generate the constants in the implementation file.
Make sure the header doesn't get changed by your script.
The easiest way to solve this is to not make those constants in a header file. Instead, make functions in the header file which get these values. Then place the values themselves in a small cpp file which implements those functions. (Or place them in a header ONLY included in that cpp file). When you recompile, only that one file will need to be recompiled.
Also, you could look in to distcc to speed up compilation if you have a few machines to spare.
If you're using gcc, you can try using ccache. it caches object files based on a hash of the preprocessed output, so will not recompile unless an actual change occured
Another way is to declare the constant values like extern const double PI; in your a header like "my_constants.h" and add one cpp file to the project with contents like:
#include "my_constants.h"
const double PI = 3.1415926535;
Then the actual values will only be compiled once, and changing a value only requires compiling that single file and linking the project again.
If you want to keep it as a single public header, you could add a pre-build step that takes your public header file and
filters out the version details, either removing them or replacing them with a fixed string, to a temp copy of the file
moves this to an internal version of your header only if it has changed, i.e. don't copy the file (+ update the timestamp) unless something other than the version has changed
then build your precompiled headers from this internal header file. You can still use the public header with the version details for the source files that need the version.
There's a moveifchanged script in the GCC sources you can borrow for this if you're on unix, or you can rig something up using fc in a batch file on Windows.
Object oriented solution:
Generally, you should put those often refreshed cnstants to cpp file, not h. Put them for example into a class. If you already have a class which creates a string of them and publish this by a method, I'd put all those constants to the same cpp and added some public methods to access them from other source files.
We have these set of "utility" constants defined in a series of file. The problem arises from the fact that TOO MANY files include these global constant files, that, if we add a constant to one of those files and try to build, it builds the whole entire library, which takes up more than an hour.
Could anyone suggest a better way for this approach? That would be greatly appreciated.
First, if you are defining them directly in the header, I'd suggest instead delcaring them extern const, and then defining them in a cpp file:
//in .hpp:
extern const std::string foo;
//in .cpp:
const std::string foo = "FOO";
That way, at least definitions can be changed without a rebuild.
Second, examine where they are being included. If the constant file is being included in a low level header, can the include be moved to the cpp instead? Removing it might lower the coupling so it doesn't have to rebuild as much.
Third, break up that file. I'd suggest mapping out a structure you'd eventually want, start adding new constants to the new structure instead of the old file. Eventually (when you are sure you've got the structure you want), refactor the old file into the new structure, and make the old file include the entire structure. Finally, go through and remove all includes of the old file, pointing them at the appropriate new sections. That'll break up the refactoring so you don't have to do it all at once.
And fourth, you might be able to trick your compiler into not rebuilding if the header file changes. You'd have to check your compiler's documentation, and it might be unsafe, so you'd occasionally want to add full builds as well.
Do you really need every global define to be included in every file? You should probably split the constants up into categories and then split them into different files.
Every .h that is included is simply copied at that point in the file that is including it. If you change something in a file (either directly or via changing something that is included) then it absolutely needs to be recompile.
Another solution would be to have a .h file that has an accessor to a map of string name/values. Then in the .cpp file of that map/accessor you can insert the new values. Every new value you put would only need 1 file to be recompiled.
Another solution is not to include the header file anywhere. Simply extern in the variables you need in each .cpp file.
Perhaps it's time to do some refactoring to improve the cohesion and reduce the coupling in your software design. Splitting the global constant files would allow modules to be more selective about which constants need to be included, which will eliminate some of the
unnecessary coupling. In the extreme case, you could break it all the way down to one constant per file, and ensure that each module only includes the constants it needs to use.
But that could result in poor cohesion, in the sense that the constants might naturally fall into related groups, such that a module that requires one constant will generally also
require many others from that group. So the trick is to find a better grouping of constants in the various global files, then ensure that each module only includes what it needs.
(Edit: I didn't think of external constants. Indeed, my idea is kinda stupid.)
(Edit: My "stupid" macro idea actually saves build time for when constants are added. Thanks for pointing that out, Brian!)
Use parallel building :-)
Seriously, I think one solution would be to create another header called utility_ex.hpp or something where you add new constants that you occasionally merge into utility.hpp (or whatever your current utility constants header is called).
Another (less efficient) solution would be to have a macro like this:
#define constant(name) get_constant(#name)
// # means turn name into a string literal
int get_constant(const char *name);
Now suppose you want MAX_CUSTOMERS to be defined as 100. You can say:
constant(MAX_CUSTOMERS)
in the code. In get_constant's code, you might have:
int get_constant(const char *name) {
if (!strcmp(name, "MAX_CUSTOMERS"))
return 100;
//shouldn't happen
return -1;
}