Search code examples
cmsvc12

Global Variable Seems To Have Two Different Addresses...?


Take into consideration the following 4 files:

[core.h]

#pragma once  
static int MY_MARK = -1;  

[count.h]

#pragma once
#include "core.h"
#include <stdarg.h>
#define Count(...) CountImpl(&MY_MARK, __VA_ARGS__, &MY_MARK)
int CountImpl(void*, ...);

[count.c]

#include "count.h"

int CountImpl(void* dummy, ...) {
    int     count = 0;
    va_list lst;

    va_start(lst, dummy);

    for(;;) {
        void* ptr = va_arg(lst, void *);
        if(ptr == &MY_MARK) {break;}
        ++count;
    }

    va_end(lst);
    return count;
}

[WeirdProblem.c]

#include <tchar.h>
#include "count.h"

int _tmain(int argc, wchar_t* argv[], wchar_t* envp[]) {
    int a = 1;
    int b = 2;
    int c = 3;
    int d = Count(&a, &b, &c);
    return 0;
}

I'm using Microsoft Visual Studio Community 2013.
When running the code above, I would expect the 'd' variable to have a value of 3. The problem is that the execution never breaks from the loop, as it does not compare 'ptr' and '&MY_MARK' to be equal. (Eventually it throws an error trying to read protected memory or whatever.)
Actually, I see two different addresses in the Watch window:

(int*)ptr       0x000000013f8d9004 {WeirdProblemTest.exe!int MY_MARK} {-1}  int *
&MY_MARK        0x000000013f8d9000 {WeirdProblemTest.exe!int MY_MARK} {-1}  int *

I know I could workaround the issue using the 'dummy' variable instead of referring to '&MY_MARK', but that's not the point.
I really need to understand what is going on, because the same problem is happening in different parts of my code and in there there's not such a nice workaround for them.

Sorry for the long post, but I found no way to keep it shorter.


Solution

  • You have both declared and defined the variable in the .h file as static which means that every file that #includes the header will get their own private copy of the variable.

    You need to split core.h into core.h and core.c looking something like:

    core.h:

    #pragma once  
    extern int MY_MARK;
    

    core.c:

    #include "core.h"
    
    int MY_MARK = -1;
    

    All other files should #include "core.h", and when compiling and linking you should link in core.c