This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

Const structures copied in RAM

Dear all,

I have some big tables constant data structures in my code, and I want them to reside in Flash. When I started few years ago, I remember I managed to do it putting quite a few const qualifiers around.

Recently I noticed, with newer versions of the compiler, that the tables are copied to RAM, wasting this precious resource.

I am using CCS latest version with compiler 5.1.3, but reverting back to 4.9.5 does not fix. I had an older compiler on my previous computer where the behavior was correct.

My question is: Is there a bug in my code that prevents the compiler to recognize the structures as constants, or there is a problem in the newer compilers?


Here is my code, simplified from the original enough to show the problem):


#include <stdio.h> extern const int ConstantInt; const int ConstantInt = 1234; typedef struct ConstantType { ConstantType(const unsigned int _a) : a(_a) {}; const unsigned int a; } ConstantType; extern const ConstantType ConstantStructure; const ConstantType ConstantStructure(1234); int main(void) { printf("%d, %d", &ConstantInt, ConstantStructure.a); return 0; }

In the above code the ConstantInt remains in Flash, while the ConstantStructure is copied to RAM.

Any Help?

  • Answering myself ...

    I noticed that removing the constructors in favor of simpler initializer lists, solves the problem, and the structures end up in Flash.

    The original reason to use constructors was that in case of simple initializers the compiler (correctly) emits the warning: class "Xxx" defines no constructor to initialize the following ...

    The warning is correct since it is not possible to initialize some const pointers to const strings that are present in my tables (and missing from the simple example above), without the constructor.

    In any case, it is interesting for me to understand why with the constructors, the tables are not recognized as constant, even if they are declared as such.

    Regards.

  • The addition of a constructor to a struct  IIRC essentially makes struct a synonym for class.  As such the compiler has to potentially bring in other overhead (vtables etc..) on a per instance basis. That may be sufficient reason for it to move the structure to RAM.

    As an aside I would never put a constructor into a struct simply because it confuses the meaning.  It took me quite a while to figure out you weren't writing C.  If a compiler were complaining in the way you mentioned I'd either ignore it or make the struct declaration explicitly C.

    Also remember C and C++ have slightly different meanings for const.  I don't think it matters here but there will be cases where it does.

     

    Robert

  • Well, struct and class are always synonym in C++, with the only difference that the first start with public members default, while the latter starts with private default, so I think this is not the difference.

    As per vtable and so on, any decent compiler will generate vtables only in presence of virtual members, which is not the case either. On the other side, vtables are constant (contain only pointer to functions), so typically should end up in flash anyway.

    You probably are right saying that declaring the structure as "C" whould solve the problem. Unfortunately, and I don't know why, but placing extern"C" { } around the declaration, doesn't change anything. The compiler still claims: "class "SimpleType" defines no constructor to initialize the following: ..."

    Of course I decided to ignore the warning, as you suggested, but I still think that the "correct" way to do it in C++, is to have constructors.

    Note that the construction is all done in the initializer list and no code is present in the constructor itself, so the compiler should be able to tell if the structure is constant and place it in flash.

    And indeed previous compiler versions did it.

    Many thanks for your answer.

  • Maurizio Ferraris said:
    . Unfortunately, and I don't know why, but placing extern"C" { } around the declaration, doesn't change anything. The compiler still claims: "class "SimpleType" defines no constructor to initialize the following: ..."

    I'd say that was a bug.  Regardless of how it should react in the C++ case it definitely should not be complaining about the lack of a constructor in a C struct.  I think doing so in the C++ case is wrong too but it is arguable.

    You are right the compiler should put the structure in ROM in either case but it isn't required to. I'd call it a bug but the compiler could be defended using the 'letter of the law'.

    I would disagree that having a constructor in a struct in C++ is the correct way of doing it.  I'd argue otherwise but the language does allow it and the compiler should support it.

    I'd be curious if a class declaration behaved the same way.  It really should but if it didn't it would provide some indication of where and how the compiler is going astray.

    Robert

  • After your replies, I investigated a little further ...

    Se the following code:

    #include <stdio.h>
    
    extern "C" {
      typedef struct SimpleCType                                                 // NOTE 1
      {
        const char * const s;
        const int a;
      } SimpleCType;
    }
    
    typedef class SimpleCppType
    {
    public:                                                                      // NOTE 2
      SimpleCppType(const char * const _s, const int _a) : s(_s), a(_a) {};      // NOTE 3
    private:
      const char * const s;
      const int a;
    } SimpleCppType;
    
    
    extern const SimpleCType AAASimpleCStructure;
    const SimpleCType AAASimpleCStructure = { "1234", 1234 };
    
    extern const SimpleCppType AAASimpleCppStructure;
    //const SimpleCppType AAASimpleCppStructure = { "1234", 1234 };              // NOTE 4
    const SimpleCppType AAASimpleCppStructure("1234", 1234);
    
    extern const SimpleCppType AAASimpleCppArray[];
    const SimpleCppType AAASimpleCppArray[] = {
      SimpleCppType("1234", 1234),
      SimpleCppType("4567", 4567),
      SimpleCppType("8901", 8901),
      SimpleCppType("2345", 2345),
    };
    
    ////////////////////////// main
    int main(void)
    {
      printf("", &AAASimpleCStructure, &AAASimpleCppStructure, &AAASimpleCppArray);
      return 0;
    }
    

    NOTE 1: The error about the missing constructor is present, and this looks like a bug

    NOTE 2: Commenting out the public: clause, causes the compiler generate a lot of errors about inaccessible members, and placing makes the class mostly like the structure above.

    NOTE 3: Removing this line does generate the warning about the missinig constructor, but allows simple "C" like structure and arrays initializers (see NOTE 4), and does put the structure in Flash

    Additionally, I believe that, even if the compiler is not "required" to place constants in Flash, in this case, I would flag it at least as a missed optimization, which, for embedded compilers, is just like a bug.

    Still looks like there is a bug somewhere ...

    Regards.

  • Absolutely agreed there are several bugs illustrated (maybe only a single source). 

    Probably worth reporting to the vendor.  You've got a nice simple test case.

    Robert

  • Well, ... vendor is TI ...

    Anyone listening here?

    Good Easter days to everyone.

  • Maurizio Ferraris said:

    Still looks like there is a bug somewhere ...

    The correct place to have these bugs looked at would be the Compiler Forum. I could move this thread to that forum, however, I would recommend starting a new post there so it doesn't get overlooked due to the discussions that have already occured. Be sure to attach the complete preprocessed source file (so we can compile it successfully), specify the compiler options used for the build, and note the areas that you think are bugs.