Memory layout of a class with only static members?

Discussion in 'C++' started by Henryk, Sep 12, 2006.

  1. Henryk

    Henryk Guest

    I have something like

    class Params {
    public:
    const static char nOne = 1;
    const static int nTwo = 2;
    const static char nThree = 3;
    };

    This is just a wrapper for globally used parameters in an embedded
    system.

    Now, I need to do a binary copy of this data to and from some Flash.
    So, what I need is the start address and the size of the data.

    Unfortunatelly, sizeof(Params) gives 1.

    I added dummy variables at the beginning and the end that can be used
    to retreive the information.

    class Params {
    public:
    const static char nBegin = 0;

    const static char nOne = 1;
    const static int nTwo = 2;
    const static char nThree = 3;

    // new parameters can be added before nEnd

    const static char nEnd = 0;
    };

    I thought that the begin is &Params::nBegin and the size of all data is
    &Params::nEnd - &Params::nBegin + sizeof(Params::nEnd).

    It works for this little test class above. But my real class contains
    much more data and a test program in VS sorts them in memory
    differently. In my case nBegin and nEnd are put together. I think for
    memory alignment reasons.

    Then I put the class in some special section and everything seems to
    work.

    My questions:

    Does it now work only by accident or is this guarantied?

    Are there any better ways to solve the problem without changing the
    general layout of the class. In my real application the parameters are
    referenced already 100s of times.

    Thank you for your comments.
     
    Henryk, Sep 12, 2006
    #1
    1. Advertising

  2. Henryk

    Goran Guest

    I don't know about the inner workings of the compiler regarding the
    layout of static members, however...

    > Now, I need to do a binary copy of this data to and from some Flash.


    You already have at least two instances of Params: in flash and, I
    guess, in your program's memory. Using static, you only get one
    instance of the thing, but it seems you have more.

    You may try like this:

    struct Params
    {
    int p1;
    int p2;
    // ...
    };

    static Params& FlashParams =
    *reinterpret_cast<Params*>(0xYOUR_PARAMS_IN_FLASH_ADDRESS_HERE);

    void Test()
    {
    int copy1 = FlashParams.p1;
    int copy2 = FlashParams.p2;
    Params RamParams = FlashParams;
    // etc...
    }

    Hey, typing-wise, it's even shorter than Params::p1!

    Of course, you need to take care not to call Test() before the
    initialization of FlashParams (highly unusual situation in my line of
    work, don't know about yours).
     
    Goran, Sep 12, 2006
    #2
    1. Advertising

  3. Henryk

    Henryk Guest

    Goran schrieb:

    > I don't know about the inner workings of the compiler regarding the
    > layout of static members, however...
    >
    > > Now, I need to do a binary copy of this data to and from some Flash.

    >
    > You already have at least two instances of Params: in flash and, I
    > guess, in your program's memory. Using static, you only get one
    > instance of the thing, but it seems you have more.


    I declared the members as static because the program must not change
    them.

    Actually I have only 1 instance in my program memory. These are the
    default parameters. But now we need some kind of parameter update
    mechanism. In Flash there is just binary data that shall be copied to
    the memory location where the static parameters reside. It's not
    another parameter instance but plain binary data (of course in the
    right format).

    > You may try like this:
    >
    > struct Params
    > {
    > int p1;
    > int p2;
    > // ...
    > };
    >
    > static Params& FlashParams =
    > *reinterpret_cast<Params*>(0xYOUR_PARAMS_IN_FLASH_ADDRESS_HERE);
    >
    > void Test()
    > {
    > int copy1 = FlashParams.p1;
    > int copy2 = FlashParams.p2;
    > Params RamParams = FlashParams;
    > // etc...
    > }


    That was my other solution but then I have to change all the code where
    parameters are referenced. Before I do this I want to be sure that
    there are no easier solutions. And, of course I would like to know what
    the standard says about this issue.

    > Hey, typing-wise, it's even shorter than Params::p1!


    Long time ago I decided to use the "class with static members" approach
    because it saves the global object (static Params ...). It looks like
    this was somehow the wrong decision... :eek:)

    Greetings

    Henryk
     
    Henryk, Sep 12, 2006
    #3
  4. Henryk

    Guest

    Henryk wrote:
    > I have something like
    >
    > class Params {
    > public:
    > const static char nOne = 1;
    > const static int nTwo = 2;
    > const static char nThree = 3;
    > };
    >
    > This is just a wrapper for globally used parameters in an embedded
    > system.
    >
    > Now, I need to do a binary copy of this data to and from some Flash.
    > So, what I need is the start address and the size of the data.


    Incorrect assumption. You assume 1 (one) start address and a contiguous
    block of memory after that. There is no reason for that. In fact, for
    alignment
    purposes, it often is better to store the chars together, the ints
    together,
    etctera. The order nTwo, nOne, nThree often is the most compact.

    HTH,
    Michiel Salters
     
    , Sep 12, 2006
    #4
  5. Henryk

    David Harmon Guest

    On 12 Sep 2006 01:45:22 -0700 in comp.lang.c++, "Henryk"
    <> wrote,
    >class Params {
    >public:
    > const static char nOne = 1;
    > const static int nTwo = 2;
    > const static char nThree = 3;
    >};


    >Now, I need to do a binary copy of this data to and from some Flash.
    >So, what I need is the start address and the size of the data.


    What data? You have three constants. There is actually no
    guarantee they are going to occupy memory at all, unless you take
    the address of each of them somewhere. There is no guarantee they
    are going to be located anywhere near each other by any kind of
    reckoning. In many cases a good compiler will just substitute the
    const values into the generated code where needed.
     
    David Harmon, Sep 12, 2006
    #5
  6. Henryk

    Henryk Guest

    David Harmon schrieb:

    > On 12 Sep 2006 01:45:22 -0700 in comp.lang.c++, "Henryk"
    > <> wrote,
    > >class Params {
    > >public:
    > > const static char nOne = 1;
    > > const static int nTwo = 2;
    > > const static char nThree = 3;
    > >};

    >
    > >Now, I need to do a binary copy of this data to and from some Flash.
    > >So, what I need is the start address and the size of the data.

    >
    > What data? You have three constants. There is actually no
    > guarantee they are going to occupy memory at all, unless you take
    > the address of each of them somewhere. There is no guarantee they
    > are going to be located anywhere near each other by any kind of
    > reckoning. In many cases a good compiler will just substitute the
    > const values into the generated code where needed.


    Const variables are ROMable and as far as I know the compiler *should*
    not replace the references by the actual values. That was one of the
    the reason we used this approach. We can change the value on one memory
    location. I checked the executable file before and this compiler (GCC
    for PowerPC) does not optimize away my const parameters.

    Back to problem, we now use a separate memory section for the parameter
    data with a known address and and a known size. So I can copy this part
    forth and back without considering any alignment issues inside this
    section.

    Henryk
     
    Henryk, Sep 12, 2006
    #6
  7. Henryk

    F.J.K. Guest

    Henryk wrote:
    > class Params {
    > public:
    > const static char nOne = 1;
    > const static int nTwo = 2;
    > const static char nThree = 3;
    > };
    >
    > Now, I need to do a binary copy of this data to and from some Flash.
    > So, what I need is the start address and the size of the data.
    >
    > Unfortunatelly, sizeof(Params) gives 1.


    I might be dense, but if you have data that needs to be changed on a
    regular base ("copy of this data ... from some Flash."), choosing const
    attributes seems to be the wrong thing to do in the first place. Sure,
    you could try to const_cast<> away the const. But after all, what stops
    the compiler from inserting known const values directly into the code,
    without any object memory reference? What stops it, from not generating
    an object in memory at all?

    I think I can deduce why you went this direction in the first place.
    You probably want to have a property API that can be queried without
    initialisation and/or construction of an object like:
    int v = a::property1
    It seems though, that you really DO need an object, if you need write
    access to it. This is a flaw in your original design.

    I think rereading the first chapters of KR would be a good idea, to get
    your head free for the Non-OO obfuscated basic language features to
    use:

    --- file a.h
    struct A {
    int property1;
    int property2;
    int property3;
    };
    extern A a;

    --- file a.cpp
    #include "a.h"
    A a={5,4,3};

    --- file main.cpp
    #include <iostream>
    #include "a.h"
    int main () {
    std::cout << "Property 1: " << a.property1 << "\n";
    std::cout << "Property 2: " << a.property2 << "\n";
    std::cout << "Property 3: " << a.property3 << "\n";
    }

    Can't get any more basic than that, can it ? ;-)
     
    F.J.K., Sep 12, 2006
    #7
  8. Henryk

    F.J.K. Guest

    Henryk wrote:

    > Const variables are ROMable and as far as I know the compiler *should*
    > not replace the references by the actual values. That was one of the
    > the reason we used this approach. We can change the value on one memory
    > location. I checked the executable file before and this compiler (GCC
    > for PowerPC) does not optimize away my const parameters.
    >
    > Back to problem, we now use a separate memory section for the parameter
    > data with a known address and and a known size. So I can copy this part
    > forth and back without considering any alignment issues inside this
    > section.
    >
    > Henryk


    Do you want your data unchangable (const) or do you want to "copy back
    and forth" (non nonst)? The time for a decision is now ;-) . Anyway, if
    you really want const, see the code in my posting below and change A
    a={5,6,7}; to const A a={5,6,7}. You'll probably use some extra flash
    routine to write to this const data and know better than I about it ;-)
     
    F.J.K., Sep 12, 2006
    #8
  9. Henryk

    Henryk Guest

    F.J.K. schrieb:

    > Henryk wrote:
    >
    > > Const variables are ROMable and as far as I know the compiler *should*
    > > not replace the references by the actual values. That was one of the
    > > the reason we used this approach. We can change the value on one memory
    > > location. I checked the executable file before and this compiler (GCC
    > > for PowerPC) does not optimize away my const parameters.
    > >
    > > Back to problem, we now use a separate memory section for the parameter
    > > data with a known address and and a known size. So I can copy this part
    > > forth and back without considering any alignment issues inside this
    > > section.
    > >
    > > Henryk

    >
    > Do you want your data unchangable (const) or do you want to "copy back
    > and forth" (non nonst)? The time for a decision is now ;-) . Anyway, if
    > you really want const, see the code in my posting below and change A
    > a={5,6,7}; to const A a={5,6,7}. You'll probably use some extra flash
    > routine to write to this const data and know better than I about it ;-)


    I know this is not consistent at some point: The parameters are const
    for SW. The const prefix saves me from changing some parameters
    accidently in my code. There is only 1 situation where the parameters
    is changed:

    Right after startup the flash is checked for valid parameter set and if
    one was found it is loaded into the memory section where the SW
    parameters reside.

    My "copy back and forth" was related to some tests I did. This is not
    operational.

    Now, based on the new requirements, I think that your and Goran's
    proposal is cleaner and the switch from the static members to a static
    object is not that big deal.

    Greets

    Henryk
     
    Henryk, Sep 12, 2006
    #9
  10. Henryk

    Noah Roberts Guest

    Henryk wrote:

    > Const variables are ROMable and as far as I know the compiler *should*
    > not replace the references by the actual values.


    Not portable, not even with the same compiler. Since a const object
    will *never* change (that is what the keyword means and the fact that
    you "can" is taken care of by the standard by saying if you do then
    your program is ill-formed and illicits undefined behavior) then the
    compiler is free to use the "as-if" (if there is no other explicit rule
    in the standard to govern this) and optimize away the actual variable.
    Since the variable never changes then optimizing it away and passing
    the value into places expecting it works "as-if" the variable existed.
    It can't do this if the address of the variable is used for any reason
    though it still can in other places (in other words you could be using
    different objects depending on how this data is used). The compiler is
    free to assume a const object will not change because if it does it is
    free to do anything at all, including not functioning at all as
    expected.

    That was one of the
    > the reason we used this approach.


    The reasoning is flawed. You'll want to stop doing it. You are
    relying on implementation defined behavior and it might not be what you
    are thinking.

    We can change the value on one memory
    > location. I checked the executable file before and this compiler (GCC
    > for PowerPC) does not optimize away my const parameters.


    const parameters or const variables? There is a big difference.

    > Back to problem, we now use a separate memory section for the parameter
    > data with a known address and and a known size. So I can copy this part
    > forth and back without considering any alignment issues inside this
    > section.


    There are no alignment issues beyond the fact that these variables are
    quite likely not aligned at all. They have no set memory layout except
    for each individual variable's given layout (ie sizeof(float) bytes in
    contiguous memory to store a float). The variables are not part of any
    instance of your class and are not necissarily anywhere near each other
    in memory (unlike if they WHERE part of your class). Your class
    actually has no size at all, but it gets one byte because it is
    necissary to be able to store variables of that type. Consider static
    variables as globals only accessable by, or through, your class...this
    link is by name only and for the compiler, it doesn't reflect compiled
    program layout.
     
    Noah Roberts, Sep 12, 2006
    #10
  11. Henryk

    F.J.K. Guest

    Henryk wrote:

    > Now, based on the new requirements, I think that your and Goran's
    > proposal is cleaner and the switch from the static members to a static
    > object is not that big deal.
    >


    Just out of interest. What _exactly_ do you think, the static attribute
    is doing to help you? I think the only thing it does is stopping you to
    see the trivial solution, id est having a global variable with the
    preference data. ;-)
     
    F.J.K., Sep 12, 2006
    #11
  12. Henryk

    David Harmon Guest

    On 12 Sep 2006 05:28:05 -0700 in comp.lang.c++, "Henryk"
    <> wrote,
    >Const variables are ROMable and as far as I know the compiler *should*
    >not replace the references by the actual values. That was one of the
    >the reason we used this approach. We can change the value on one memory
    >location. I checked the executable file before and this compiler (GCC
    >for PowerPC) does not optimize away my const parameters.


    But you asked "Does it now work only by accident or is this
    guarantied?" The answer as far as the c++ standard is concerned is,
    not only is it not guaranteed, but much less is guaranteed that you
    seem to be supposing. Anything about const variables being ROMable
    is outside those guarantees.

    If you are looking for a solution that has some basis in guarantees
    made by the language, then I would be proposing something along the
    lines of:

    1. Abandon static members. They offer just about nothing in the way
    of guarantees about layout in memory.

    2. Create your variables as members (not static members) of a POD
    struct. That's just about the only thing that comes close to any
    guarantee about layout in memory.

    3. Use a const instance of the struct for initialization. Something
    of the form below should *I hope* be ROMable:
    static const Params initial_params = { 1, 2, 3 };

    4. Use a non-const instance for the copy in RAM. Then you are
    indeed guaranteed that it has the same POD layout as the ROM and can
    be copied right over.
     
    David Harmon, Sep 12, 2006
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. SaravanaKumar
    Replies:
    6
    Views:
    9,446
    Tony Morris
    Oct 19, 2004
  2. JFCM
    Replies:
    4
    Views:
    5,753
  3. CoolPint
    Replies:
    8
    Views:
    1,000
    Jeff Schwab
    Dec 14, 2003
  4. Replies:
    1
    Views:
    603
    John Timney \(MVP\)
    Jun 19, 2006
  5. Hicham Mouline
    Replies:
    5
    Views:
    2,403
    James Kanze
    Dec 19, 2008
Loading...

Share This Page