Генерация случайного идентификатора в препроцессоре C, чтобы избежать дублирования символов компоновщика

Я пытаюсь решить, может ли Xcode сказать мне, если я забуду включить реализацию категории в мою цель? и я придумал следующее решение:

NSObject + foo.h

extern int volatile canary;
void canaryCage() {
  canary = 0;
}

NSObject + Foo.m

int canary = 0;

Теперь, если я #import "NSObject+Foo.h" в исходном файле я получу ошибку компоновщика, если это NSObject+Foo.m не был также включен в мою цель.

Однако каждый раз, когда я #import "NSObject+Foo.h" Я создаю дубликат _canaryCage условное обозначение. Я не могу использовать __COUNTER__ потому что я только #import "NSObject+Foo.h" в файлах реализации. я нуждаюсь canaryCage быть уникальным во всей моей таблице символов.

Мне нужно что-то вроде:

#define CONCAT(x, y) x##y
#define CONCAT2(x, y) CONCAT(x, y)
extern int volatile canary;
void CONCAT2(canaryCage, __RANDOM__)() {
  canary = 0;
}

Таким образом, если у меня есть исходные файлы, такие как:

Bar.m

#import "NSObject+Foo.h"

Baz.m

#import "NSObject+Foo.h"

Я получу символы как _canaryCage9572098740753234521 а также _canaryCage549569815492345, который не будет конфликтовать. Я тоже не хочу включать --allow-multiple-definition в ld потому что я хочу, чтобы другие повторяющиеся определения символов вызывали ошибку. Я не хочу использовать canaryCage для чего-либо, кроме маркера, который я забыл связать исходный файл, заголовок которого я #importредактор

2 ответа

Решение

Этот ответ был близок, но это привело к canaryCage быть оптимизирован, потому что это был мертвый код.

Решение:

NSObject + foo.h

extern int canary;
__attribute__((constructor)) static void canaryCage() {
  canary = 0;
}

NSObject + Foo.m

int canary = 0;

К сожалению, это добавляет некоторые накладные расходы каждый раз, когда категория импортируется, но накладные расходы очень минимальны. Если кто-нибудь знает способ предотвратить canaryCage от того, что меня раздели, я с радостью отмечу их ответ как правильный.

Если вы сделаете это staticкаждая единица перевода получит свою собственную копию, а все остальное должно работать так, как вы этого хотите - никакой гимнастики препроцессора не требуется.

static void canaryCage()
{
    canary = 0;
}
Другие вопросы по тегам