Michael Forrest
Michael Forrest

Reputation: 3511

Address of static variable changes between static inline function calls

I'm not great at C (I'm an iOS developer) so this one's confusing me:

I've got a header file where I define some localisation helpers:

#ifndef LocalizationMacros_h
#define LocalizationMacros_h

static NSString * forcedLanguage = nil;

static inline void forceLanguage(NSString*language){
    NSLog(@"Forcing language %@ (%i)", language, &forcedLanguage);
    // Output: Forcing language de (5248160)

    forcedLanguage = language;
}

static inline NSString * translate(NSString * language, NSString * key){
    NSLog(@"Forced language: %@ (%i)", forcedLanguage, &forcedLanguage);
    // Output: Forced language: (null) (5248236)

    // ... do some stuff to put translation into result ...
    return result;
}

#endif

I don't understand why the address of forcedLanguage changes between forceLanguage() and translate(), resulting in (null) as its value. Can somebody enlighten me?

Upvotes: 0

Views: 70

Answers (2)

Clifford
Clifford

Reputation: 93476

The static keyword localises the object to the translation unit in which it is placed - you have placed it in a header file, so it can be included in multiple translation units.

Here static is being used as a linkage modifier; in this context it is not a storage class specifier - all data declared outside of a function will have static storage class in any case. What you want here is to make it global (a matter of fact rather than recommendation) - i.e. to give it extern linkage. External linkage is the default whether you declare it extern or not.

If you give it external linkage, then the header must contain only a declaration, not an instantiation - the instantiation must be in a single translation unit.

Upvotes: 2

Paul R
Paul R

Reputation: 212979

You are defining a copy of the forcedLanguage variable for every source file that includes your header. In your header change:

static NSString * forcedLanguage = nil;

to:

extern NSString * forcedLanguage;

and then in one source file (ideally the one that corresponds with your header) define:

NSString * forcedLanguage = nil;

For future reference, the rule of thumb is: variable declarations go in header files, variable definitions go in source files.

Upvotes: 4

Related Questions