Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. [Solved] Using constants in several cpp files
Forum Updated to NodeBB v4.3 + New Features

[Solved] Using constants in several cpp files

Scheduled Pinned Locked Moved General and Desktop
11 Posts 7 Posters 4.7k Views 1 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • dheerendraD Offline
    dheerendraD Offline
    dheerendra
    Qt Champions 2022
    wrote on last edited by
    #2

    Define once in some file and use extern keyword ?

    Dheerendra
    @Community Service
    Certified Qt Specialist
    http://www.pthinks.com

    1 Reply Last reply
    0
    • hskoglundH Offline
      hskoglundH Offline
      hskoglund
      wrote on last edited by Chris Kawa
      #3

      Another trick is to prefix them with "static" e.g:

      static const char *STR_NEWLINE = "\n";
      
      1 Reply Last reply
      0
      • A Offline
        A Offline
        andreyc
        wrote on last edited by
        #4

        Just don't forget that with static you may get two separate constants. One per file. Double memory usage. I know that with 32G on board it is not big issue. But who knows.

        I said "may" because I don't know if and how a compiler can optimize it.

        1 Reply Last reply
        0
        • S Offline
          S Offline
          StephanWoebbeking
          wrote on last edited by
          #5

          Hi, sorry I never replied before, but I was busy working on other corners of the project. In the meanwhile I have introduced quite a lot of constants which I just think is useful to be grouped in a constants file. So I have this constant object with a lot of "static const ..." definitions which I would say is fine. In includes I have received from other parts of the project I find a lot of preprocessor #defines...

          Now, I come from the Java corner and appreciate the limited scope of the constants object and the constants within. From the principal point of view, how would you all recommend to do it? Do you have specific reasons to do it one way or the other? What's the silver bullet - if there is one - to it?

          Stephan

          1 Reply Last reply
          0
          • raven-worxR Offline
            raven-worxR Offline
            raven-worx
            Moderators
            wrote on last edited by Chris Kawa
            #6

            So I have this constant object with a lot of "static const ..." definitions which I would say is fine.

            the problem with that is, that each file which includes the header file with the static variables gets it's own copy of the variable. Which no idead especially when using a lot of such constants and/or complex types.

            So to make sure the variable is only initialized once in the whole app/lib (the same same memory for all includes) follow Dheerendra suggestion:

            in the constants.h file:

            extern const int MY_CONSTANT;
            

            then in a .cpp (e.g. constants.cpp)

            const int MY_CONSTANT = 0;
            

            --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
            If you have a question please use the forum so others can benefit from the solution in the future

            1 Reply Last reply
            0
            • S Offline
              S Offline
              StephanWoebbeking
              wrote on last edited by
              #7

              Ok, right, I missed that again... Now, the header file is - as usual - prefixed with the #ifdef, #define combination. If I remove the static, then I receive the multiple definition error. But why, would the #ifdef, #define not omit the multiple compilation of the code? Well, why does it not solved this? And if it doesn't, why the heck do we write it all the time?

              Carries us to the format you have suggested before with declaration in the header and definition in the source file. But that's a lot of double typing, I would suggest a rather error prone approach. Does this suggests to resign to the use of preprocessor #defines for constants definitions?

              Stephan

              1 Reply Last reply
              0
              • S Offline
                S Offline
                StephanWoebbeking
                wrote on last edited by
                #8

                No "best practice" suggestions with regard to this topic?

                1 Reply Last reply
                0
                • Chris KawaC Online
                  Chris KawaC Online
                  Chris Kawa
                  Lifetime Qt Champion
                  wrote on last edited by Chris Kawa
                  #9

                  Well, why does it not solved this?

                  You need to build a mental image of how compilation and linking works to answer this.
                  To simplify - compilers don't compile headers. They only compile .cpp files and before they do they sorta copy/paste text from header into the cpp. Then each cpp gets compiled into a separate object file. After that linker gets these object files and glues them together to form the resulting library/executable.

                  Knowing that consider this example:

                  //foo.h
                  const int variable;
                  
                  //bar.cpp
                  #include "foo.h"
                  
                  //bazz.cpp
                  #include "foo.h"
                  

                  This pastes foo.h in both cpps. Compiler happily compiles this and creates two object files bar.obj and bazz.obj, both of which contain a variable. Now linker takes these and tries to glue them together. Ups.. it has two symbols called "variable". It throws an error.

                  Now surround the .h with #ifdef and... it changes nothing. It gets pasted into cpps just the same and the linker will still give an error. Bummer.

                  Now let's throw a static into the mix. static means a variable definition with object file scope i.e it still gets copy/pasted into the cpps and creates one symbol for each file but "scoped" to that file. Sorta like a namespace, just implicit. You can't access bar's copy of the variable from bazz and you can't access bazz's copy from bar so there's no clash. You have two objects but they don't look the same to the linker. It uses copy from bar in bar.obj code and copy from bazz in code from bazz.obj.
                  That being said a word of caution here. It's kinda dangerous if you mix it with #ifdefs, like so:

                  //foo.h
                  #ifdef BLAH
                  static const int variable = 42;
                  #else
                  static const int variable = 24;
                  #endif
                  
                  //bar.cpp
                  #include "foo.h" // will put variable with value 24 into the bar.obj
                  
                  //bazz.cpp
                  #define BLAH
                  #include "foo.h" // will put variable with value 42 into the bazz.obj
                  

                  So you see that it can lead to situation that you seem to be using the same constant, but it gets a different value depending on which part of your code uses it. Scarry to debug ;) My personal recommendation here: don't do it.

                  As for the extern it does something else. an extern means more or less "Please compiler, don't create an object of this variable. I'm just hinting to you that there will be a variable like this somewhere in the program but let linker worry about it. Just pretend it's defined but don't define it yourself." Then you have this variable really typed in some cpp, this time without extern, so it gets created by the compiler. It doesn't yet know it's the same thing it just creates some variable object like it was defined only i that cpp. After that the linker steps in, sees that variable and says "oh, that's the variable you were mentioning with the extern keyword. I'll beter put it now wherever it was mentioned.". Problem solved.
                  It doesn't fall into that #ifdef trap because now the variable is defined in a single place and just hinted at (with extern) in multiple. If you happen to define a variable called like this in some other cpp you will get the linker's (un)friendly multiple definition error again. A little more typing but safer. My personal choice.

                  And if it doesn’t, why the heck do we write it all the time?

                  The include guards (#ifdefs) are not intended to protect from multiple definition. They protect from multiple declaration. Consider this example:

                  //foo.h
                  class A {};
                  
                  //bar.h
                  #include "foo.h"
                  
                  //bazz.h
                  #include "foo.h"
                  
                  //some.cpp
                  #include "bar.h"   // declares A
                  #include "bazz.h"  // declares A... again? Um.. so which one do you mean?
                  

                  This time it's the compiler that throws an error. Not the linker. The compiler has a cpp with two declarations of A so it protests.

                  Now let's fix this:

                  //foo.h
                  #ifndef FOO
                  #define FOO
                  class A {};
                  #endif
                  
                  //bar.h
                  #include "foo.h"
                  
                  //bazz.h
                  #include "foo.h"
                  
                  //some.cpp
                  #include "bar.h"   // defines FOO, declares A
                  #include "bazz.h"  // FOO is defined so it does nothing
                  

                  Now there's a single declaration of A and compiler is happy.

                  Hope nobody fell asleep reading this ;)

                  P 1 Reply Last reply
                  3
                  • S Offline
                    S Offline
                    StephanWoebbeking
                    wrote on last edited by Chris Kawa
                    #10

                    Hope nobody fell asleep reading this ;)

                    Definitely not. Even all this sounds familiar, somehow I was still having question marks in my mind. After reading this it seems to be much clearer! I may have been mixing up concepts of Java, C, C++, Delphi in my mind which all of them I have to use often in parallel - depending on the project. So this pulled me back to the red thread, thanks for that. :o)

                    Stephan

                    1 Reply Last reply
                    0
                    • Chris KawaC Chris Kawa

                      Well, why does it not solved this?

                      You need to build a mental image of how compilation and linking works to answer this.
                      To simplify - compilers don't compile headers. They only compile .cpp files and before they do they sorta copy/paste text from header into the cpp. Then each cpp gets compiled into a separate object file. After that linker gets these object files and glues them together to form the resulting library/executable.

                      Knowing that consider this example:

                      //foo.h
                      const int variable;
                      
                      //bar.cpp
                      #include "foo.h"
                      
                      //bazz.cpp
                      #include "foo.h"
                      

                      This pastes foo.h in both cpps. Compiler happily compiles this and creates two object files bar.obj and bazz.obj, both of which contain a variable. Now linker takes these and tries to glue them together. Ups.. it has two symbols called "variable". It throws an error.

                      Now surround the .h with #ifdef and... it changes nothing. It gets pasted into cpps just the same and the linker will still give an error. Bummer.

                      Now let's throw a static into the mix. static means a variable definition with object file scope i.e it still gets copy/pasted into the cpps and creates one symbol for each file but "scoped" to that file. Sorta like a namespace, just implicit. You can't access bar's copy of the variable from bazz and you can't access bazz's copy from bar so there's no clash. You have two objects but they don't look the same to the linker. It uses copy from bar in bar.obj code and copy from bazz in code from bazz.obj.
                      That being said a word of caution here. It's kinda dangerous if you mix it with #ifdefs, like so:

                      //foo.h
                      #ifdef BLAH
                      static const int variable = 42;
                      #else
                      static const int variable = 24;
                      #endif
                      
                      //bar.cpp
                      #include "foo.h" // will put variable with value 24 into the bar.obj
                      
                      //bazz.cpp
                      #define BLAH
                      #include "foo.h" // will put variable with value 42 into the bazz.obj
                      

                      So you see that it can lead to situation that you seem to be using the same constant, but it gets a different value depending on which part of your code uses it. Scarry to debug ;) My personal recommendation here: don't do it.

                      As for the extern it does something else. an extern means more or less "Please compiler, don't create an object of this variable. I'm just hinting to you that there will be a variable like this somewhere in the program but let linker worry about it. Just pretend it's defined but don't define it yourself." Then you have this variable really typed in some cpp, this time without extern, so it gets created by the compiler. It doesn't yet know it's the same thing it just creates some variable object like it was defined only i that cpp. After that the linker steps in, sees that variable and says "oh, that's the variable you were mentioning with the extern keyword. I'll beter put it now wherever it was mentioned.". Problem solved.
                      It doesn't fall into that #ifdef trap because now the variable is defined in a single place and just hinted at (with extern) in multiple. If you happen to define a variable called like this in some other cpp you will get the linker's (un)friendly multiple definition error again. A little more typing but safer. My personal choice.

                      And if it doesn’t, why the heck do we write it all the time?

                      The include guards (#ifdefs) are not intended to protect from multiple definition. They protect from multiple declaration. Consider this example:

                      //foo.h
                      class A {};
                      
                      //bar.h
                      #include "foo.h"
                      
                      //bazz.h
                      #include "foo.h"
                      
                      //some.cpp
                      #include "bar.h"   // declares A
                      #include "bazz.h"  // declares A... again? Um.. so which one do you mean?
                      

                      This time it's the compiler that throws an error. Not the linker. The compiler has a cpp with two declarations of A so it protests.

                      Now let's fix this:

                      //foo.h
                      #ifndef FOO
                      #define FOO
                      class A {};
                      #endif
                      
                      //bar.h
                      #include "foo.h"
                      
                      //bazz.h
                      #include "foo.h"
                      
                      //some.cpp
                      #include "bar.h"   // defines FOO, declares A
                      #include "bazz.h"  // FOO is defined so it does nothing
                      

                      Now there's a single declaration of A and compiler is happy.

                      Hope nobody fell asleep reading this ;)

                      P Offline
                      P Offline
                      Porchezhiyan E
                      wrote on last edited by Porchezhiyan E
                      #11

                      @Chris-Kawa You Kidding? Your explanation was very interesting, clear and easy to understand. Thank you very much.
                      I loved the below line,
                      "Please compiler, don't create an object of this variable. I'm just hinting to you that there will be a variable like this somewhere in the program but let linker worry about it. Just pretend it's defined but don't define it yourself."

                      1 Reply Last reply
                      0

                      • Login

                      • Login or register to search.
                      • First post
                        Last post
                      0
                      • Categories
                      • Recent
                      • Tags
                      • Popular
                      • Users
                      • Groups
                      • Search
                      • Get Qt Extensions
                      • Unsolved