Адрес статической переменной изменяется между вызовами статических встроенных функций

#objective-c #c

#objective-c #c

Вопрос:

Я не силен в C (я разработчик iOS), так что это меня смущает:

У меня есть файл заголовка, в котором я определяю некоторые помощники по локализации:

 #ifndef LocalizationMacros_h
#define LocalizationMacros_h

static NSString * forcedLanguage = nil;

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

    forcedLanguage = language;
}

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

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

#endif
  

Я не понимаю, почему адрес forcedLanguage изменяется между forceLanguage() и translate() , что приводит к (null) его значению. Может кто-нибудь просветить меня?

Комментарии:

1. Я предполагаю, что inline это приводит к созданию отдельного статического файла, локального для каждой единицы компиляции. Находятся ли ваши два метода в разных единицах компиляции?

Ответ №1:

Вы определяете копию forcedLanguage переменной для каждого исходного файла, который включает ваш заголовок. В вашем изменении заголовка:

 static NSString * forcedLanguage = nil;
  

Для:

 extern NSString * forcedLanguage;
  

а затем в одном исходном файле (в идеале в том, который соответствует вашему заголовку) определите:

 NSString * forcedLanguage = nil;
  

Для дальнейшего использования, эмпирическое правило таково: объявления переменных хранятся в заголовочных файлах, определения переменных — в исходных файлах.

Ответ №2:

static Ключевое слово локализует объект в единицу перевода, в которую он помещен — вы поместили его в заголовочный файл, поэтому его можно включить в несколько единиц перевода.

Здесь static используется как модификатор связи; в данном контексте это не спецификатор класса хранения — все данные, объявленные вне функции, в любом случае будут иметь статический класс хранения. Здесь вы хотите сделать его глобальным (фактически, а не рекомендацией), т. Е. Дать ему extern связь. Внешняя связь используется по умолчанию, независимо от того, объявляете вы ее extern или нет.

Если вы предоставляете ему внешнюю связь, то заголовок должен содержать только объявление, а не экземпляр — экземпляр должен быть в одной единице перевода.

Комментарии:

1. Вы имеете в виду «единицу компиляции» (в отличие от «единицы перевода»)? Я думаю, что приму этот ответ, хотя оба хороши, потому что это объясняет, почему немного больше.

2. единица компиляции / единица преобразования — это одно и то же. en.wikipedia.org/wiki/Translation_unit_ (программирование)