Наши партнеры

UnixForum





Библиотека сайта rus-linux.net

На главную -> MyLDP -> Программирование и алгоритмические языки


Ulrich Drepper "Как писать разделяемые библиотеки"
Назад Оглавление Вперед

B. Автоматический обработчик массивов указателей строк

В методе обработки массивов указателей строк, представленном в разделе 2.4.3, показан только принцип построения структур данных, для которых перемещения не нужны. Но та конструкция корявая и подвержена возникновению ошибок. Копирование строк в несколько мест, указываемое в исходном коде, всегда сопряжено с проблемой синхронизации строк.

Бруно Хайбл (Bruno Haible) предложил нечто подобное для автоматического создания таблиц. Программист лишь добавляет в файл данных, который используется при компиляции, строки, помеченные соответствующим образом. Фактический код фреймворка выглядит следующим образом:

#include <stddef.h>

#define MSGSTRFIELD(line) MSGSTRFIELD1(line)
#define MSGSTRFIELD1(line) str##line
static const union msgstr_t {
	struct {
#define _S(n, s) char MSGSTRFIELD(__LINE__)[sizeof(s)];
#include "stringtab.h"
#undef _S
	};
	char str[0];
} msgstr = { {
#define _S(n, s) s,
#include "stringtab.h"
#undef _S
}  };
static const unsigned int msgidx[ ] = {
#define _S(n, s) [n] = offsetof(union msgstr_t, MSGSTRFIELD(__LINE__)),
#include "stringtab.h"
#undef _S
};
const char *errstr (int nr) {
	return msgstr.str + msgidx[nr];
}

Строка данных должна находиться в файле stringtab.h. Для примера из раздела 2.4.3 данные будут выглядеть следующим образом:

_S(ERR1, "message for err1")
_S(ERR3, "message for err3")
_S(ERR2, "message for err2")

Макрос S имеет два параметра: первый является индексом, используемым для поиска строки, а второй является самой строкой. Порядок, в котором строки указываются, не важен. Значение первого параметра используется для того, чтобы поместить смещение в соответствующий хэш-блок массива. Чтобы увидеть результаты, нужно выполнить эти исходные коды с использованием препроцессора. Такой способ обработки массивов строк обладает явным преимуществом, поскольку строки нужно указывать только в одном месте и порядок, в котором они указываются, не важен. В противном случае оба этих аспекта могли бы легко привести к очень трудно обнаруживаемым ошибкам.

В данном случае в массиве msgidx используется тип unsigned int, который в большинстве случаев равен 32 битам. Как правило, это слишком много для адресации всех байтов в в коллекции строк в msgstrn. Поэтому если возникнет вопрос с размером, то можно использовать тип uint16 t или даже тип uint8 t.

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


Предыдущий раздел:   Следующий раздел:
Назад Оглавление Вперед