0

If I define a large constant string in a header file that is included multiple times, will it create multiple copies of the constant string in the executable? (If it does, is there a way to avoid this without needing a separate source file?)

This is what the header looks like:

#pragma once
// this is generated by a tool, so keeping it in one header makes life easy
const uint32 TABLE_SIZE = 65536; 
const uint8 TABLE[TABLE_SIZE] = {...};
Anne Quinn
  • 12,609
  • 8
  • 54
  • 101
  • `#pragma once` or header guards do not prevent inclusion in multiple translation units. – drescherjm Dec 18 '17 at 17:11
  • 1
    This may help https://msdn.microsoft.com/en-us/library/5tkz6s71.aspx?ranMID=24542&ranEAID=TnL5HPStwNw&ranSiteID=TnL5HPStwNw-PlqXSGU6tZLZUC_D0BdChQ&tduid=%284a10f56c3090d524e46dacf26dab1d8c%29%28256380%29%282459594%29%28TnL5HPStwNw-PlqXSGU6tZLZUC_D0BdChQ%29%28%29&f=255&MSPPError=-2147217396 – Kakalokia Dec 18 '17 at 17:18
  • I did some research into how stb_image.h handles it's header-only implementation and have found a working solution, that I'll be leaving as an answer – Anne Quinn Dec 18 '17 at 17:34
  • 1
    Even, if possible to do it, are you sure you want every file to compile slowly because of huge header? And generating a source file is not harder that an header file. And generating a pair of files is not much harder... And why not loading data from an external file (or embedded resource)? – Phil1970 Dec 18 '17 at 17:49
  • Why don't you just generate a private header that is included by 1 cpp file. Then a public header that declares the extern? – drescherjm Dec 18 '17 at 17:52
  • @drescherjm - that might be hard, the generated header belongs in a project that statically links to a .lib where the public header and .cpp file would need to be. (the .lib is used across multiple projects, but the generated .h is unique to each one) – Anne Quinn Dec 18 '17 at 17:59
  • You can declare the array to be `inline` after C++17. – xskxzr Dec 18 '17 at 18:04

2 Answers2

0

In C++, a const variable defined at file scope has internal linkage only, i.e. it's only visible in that translation unit. Defining it in a header file should therefore not cause any errors about multiple definitions.

Thus each include will produce new copy of the buffer.

Sometimes you can prevent it for example in MSVC for const strings with the option /GS. But it will be not working for char array initializers like yours, it is for const char* p = ... only.

If it does, is there a way to avoid this without needing a separate source file?

No, there is not.

273K
  • 29,503
  • 10
  • 41
  • 64
0

Looked into how stb_image.h handles it's header-only implementation and found a workable way to include the large string only once in the executable:

The header now looks like this:

#pragma once

// #define IMPLEMENT_TABLE in one and only one cpp file 
// before including this header to define the table

const uint32 TABLE_SIZE = 65536; 
extern const uint8 TABLE[TABLE_SIZE];

#ifdef IMPLEMENT_TABLE

const uint8 TABLE[TABLE_SIZE] = {...};

#endif
Anne Quinn
  • 12,609
  • 8
  • 54
  • 101
  • 3
    Now you need to define IMPLEMENT_TABLE while compiling exactly one cpp file. Is this really easier than just adding the definition right to that cpp file? – n. m. could be an AI Dec 18 '17 at 17:47
  • The define just needs to be in one .cpp file, probably main.cpp. Every other translation unit can include the header file normally. And yes, the header is generated by a tool outside the IDE, keeping it localized to one file that the IDE doesn't need to know about keeps things organized – Anne Quinn Dec 18 '17 at 17:51
  • 1
    I recommend you to define `TABLE_SIZE` as `inline constexpr` after C++17. Then you can use it in contexts where a const expression is required, and all `TABLE_SIZE`s in different translation units denote the same entity. – xskxzr Dec 18 '17 at 17:55