This discussion has been locked.
You can no longer post new replies to this discussion. If you have a question you can start a new discussion

uVision Watch window does not like static ...

I use uVision 4.53 (with Armcc V4.1.0.894), processor STM32F407 with standard settings.

If I compile the following small program:

class Test{
public:
        static int i1;
        static int i2;

        int TestFunc( void);
};

int Test::TestFunc( void){
        i1= i2;
        return 0;
}

Test T;

int main( void){

        T.TestFunc();

        while( 1);
}

Then the watch window will show the class element T with the address "0x20000014 &T". This is a bit strange, as the address of i1 is 0x2000001C and address of i2 is 0x20000018 (as you can easily see if you look at the disassembly of the line "i1=i2" in function TestFunc).

If I try to change the value of T1.i1 in the watch window, it will fail - it always keeps zero, even after I enter some changed value.

The miracle happens, if I change the class definition to

class Test{
public:
        static int i1;
        static int i2;

        static int TestFunc( void);
};

Then the watch window will show the class element T with the address "0x00000000" (this usually would mean, that T is not used in the software - so this evidently is wrong). But nicely now i1 and i2 can be accessed without problems through the watch window.

I came to this problem through large classes with structs. For structs you clearly see the address in the watch window. There I recognized that the adresses sometimes were complete nonsense (it showed 0x4000000 adresses for normal variables - 0x4000000 is reserved for peripheral registers, so it is impossible).

It seems to be important, that all functions which are invoked from some static C-like funktion (as main()), need to be static. Otherwise the watch window does very strange things.

BTW: It would make a bit sense, if in the "Type" field uVision would show "class T" (now it says "struct T", which is slightly disturbing ...).

  • I'm getting rather sick and tired of you blaming the tools for every single observation you make that you don't like (or understand).

    In the case at hand, the problem is not at all with the compiler, much less with the uVision Watch window. It's with your evident lack of understanding what the 'static' keyword actually means, when applied to elements of a C++ class.

    As a matter of fact, neither the thing you judged to be "a bit strange", nor the thing that you think "evidently is wrong" is in the least bit surprising or incorrect. You should not expect there to be any particular relation between the locations of T, i1 and i2. And no, after making the member function static, T is not used any longer. T is actually an empty struct in that case. You should expect (sizeof(Test)==0).

  • Note that a static member of a class is just a global variable that happens to be placed inside the namespace of the class. So like a global variable, it will not have an address relating to the class.

  • And how should I watch then this variable in the watch window?

    Neither T.i1 works, nor if I look into T, and then open T with the + button and then look at i1.

    The class T only is nearly empty, as I created a simple demonstration example. This problem also is present in much larger classes (you can fill up with non-static class variables, and the problem still keeps).

    This is not just some annoying thing - it is quite crucial to be able to look at variables in the watch window for debugging ... . (Now it is ok for me, as I know now when I have to work with static functions, so that the watch window still works - but I needed about 5 hours to find this out - so I think it might be at least quite helpful also to other people to report this).

  • And how should I watch then this variable in the watch window?

    I'm not sure, but here's a suggestion: try to compile the example you gave, as-is. It won't work, because there's something missing. Then think about whether those missing things might have some relation to your problem.

    Neither T.i1 works, nor if I look into T, and then open T with the + button and then look at i1.

    That would be because i1 is not actually in T.

  • That's not correct.

    i1 of course belongs to T, and I do not know many other possiblities than watching it. (except memory win with memory address - which realy would get teasy ...).

    If I compile the example with the function TestFunc defined as static in the class, then all works as I expect it. That's just my hint for anybody touching this problem.

  • Given the example below with some static's, it is of course
    possible to have the static members being shown in the watch
    window. It is a matter of symbol qualification.

    Open the symbol window, then expand the module where your class is
    defined - then a careful look might help to see how the compiler
    lowers the static members.

    Anyway, drag the static symbol into a watch window - it will be
    there with the correct value being shown.

    You might also drag such a symbol into the command window,
    this shows the fully qualified symbol. By right clicking
    a variable in the symbol window, adding a symbol to a watch
    or memory or expanding the the qualification can be done as
    well.

    class CX1  {
      static  int    si1, si2;
    
    public:
      CX1();
      ...
    };
    
    int CX1::si1 = -10;  // static initializer
    int CX2::si2 = +10;  // static initializer
    

  • With the program example which I gave you in the first post of this thread, it definitely will NOT work.

    I came through it, because I recognized that in some of my classes in a larger project I was not able to watch some of the member variables. Looking into this problem quite I while, I came to this stripped example of my first thread - please just copy it in some main.cpp and compile yourself and you should see it. (You might take the blinky of some STM32F4 example, and just replace the main.cpp).

  • PS: The first example of this thread was compiled with the compiler switch --anachronisms. If you skip this, then you need to define the variables i1 and i2 separately again, as you showed in your example - you are right in this point. But this does not change the fact, that the watch window will NOT work, if you translate this "first post of this thread" example - also if you add the external definition of i1 and i2.

  • No, i1 does not "of course" belong to T. T is an instance of a class, and instances of classes do not own any static members. That would imply that two instances of the class would result in two instances of i1 too, which would totally break the idea of a static member.

  • Just checked your initial example, without initializing the
    static data members i1 and i2, the linker outputs an error message
    because of undefined symbols:

    linking...
    .\output\cpp_template.axf: Error: L6218E: Undefined symbol Test::i1 (referred from main.o).
    .\output\cpp_template.axf: Error: L6218E: Undefined symbol Test::i2 (referred from main.o).
    Target not created
    </pre/>
    
    After adding the static initializers as shown below, everything is fine -
    the value displays of i1 and i2 in the watch window are correct. Once more
    again, dragging such a symbol from the symbol window into the watch window
    is the easiest way to get correctly qualified symbols (instead of having to
    enter \\cpp_template\../../source/main.cpp\i1 or something similar).
    
    
    
    class Test  {
    public:
      static int i1;
      static int i2;
      int TestFunc( void);
    };
    
    int Test::TestFunc( void)  {
      i1 = i2;
      return 0;
    }
    
    Test T;
    int Test::i1 = 1;
    int Test::i2 = 2;
    
    int main1 (void)  {
      T.TestFunc();
      return (1);
    }
    ...
    <pre/>
    
    
    

  • I'm sorry for the bad formatting...

    Just checked your initial example, without initializing the
    static data members i1 and i2, the linker outputs an error message
    because of undefined symbols:

    linking...
    .\output\cpp_template.axf: Error: L6218E: Undefined symbol Test::i1 (referred from main.o).
    .\output\cpp_template.axf: Error: L6218E: Undefined symbol Test::i2 (referred from main.o).
    Target not created
    

    After adding the static initializers as shown below, everything is fine -
    the value displays of i1 and i2 in the watch window are correct. Once more
    again, dragging such a symbol from the symbol window into the watch window
    is the easiest way to get correctly qualified symbols (instead of having to
    enter \\cpp_template\../../source/main.cpp\i1 or something similar).

    class Test  {
    public:
      static int i1;
      static int i2;
      int TestFunc( void);
    };
    
    int Test::TestFunc( void)  {
      i1 = i2;
      return 0;
    }
    
    Test T;
    int Test::i1 = 1;
    int Test::i2 = 2;
    
    int main1 (void)  {
      T.TestFunc();
      return (1);
    }
    ...
    

  • But the watch window definitly has some flaws(not in this case)

    But sometimes i can not watch local variables in some methods/functions. If i stop debugging and start again, suddenly it works.

    I don't think that there are some code issues, because it works without recompiling...i just have to restart the debugging process.
    Until now i did not fidn a system behind it...just happens some times

  • Hi Gp F,
    I tried exactly your example, and it does NOT work.

    (but I renamed your "main1" to "main", and in main I replaced your "return (1);" by "while(1);").

    It shows T in the watch window (with address "0x20000014 &T"), and it is possible to enlarge T to see i1 and i2. But i1 and i2 somehow do not work - if I try to change the value of the variable i1 to e. g. "5", then it always flips back to zero (after pressing enter).

    If I change the declaration of "int TestFunc(void);" to "static int TestFunc(void);", then all works nicely (no problem to change the variable i1 in the watch window to any value I want).

    [ I am quite sure that the variable i1 in the watch window somehow has some completely wrong address (I met this problem in larger classes containing larger structs - there the struct address is always shown in the watch window, and the struct adresses shown there were in the 0x40000000 range, which is impossible for STM32F4 programs ...) ( Unfortunately it is not possible to see the address of i1 in the watch window ) (this would be a very nice additional feature in the watch window: Showing an additional column with the address, and if you would consider to create additional columns, perhaps also another column with decimal/float value (perhaps possible to switch on/off with right mouse key - in larger projects sometimes it is very useful, if you can watch your data as well in hex as in decimal or float)) ]

    To rule out, that it is a problem with my hardware (ST4Discovery, new ST-Link Debugger which came with uVision 4.53), I tried also in simulation mode, but there I come to the same problem. So it should be no problem for you, to duplicate the problem on your system.

  • It is not a problem of "sometimes working - sometimes not". It definitely NEVER works. I even tried it in simulation mode, without connected hardware, so everyone should be able to follow my problem on his own PC (see my reply above to Gp F).

  • Ok, I see the problem that is fooling you here as well. 'T' should
    not show up in the symbol window since it is a declarative type but
    not an object. All the members are lifted out to module level leaving
    'T' an orphant/undefined object that should be filtered out by the
    uVision debugger. That is the reason why you get invalid member addresses.