Библиотека сайта 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, и поэтому они не только хранятся в сегменте данных, доступном только для чтения, и становятся разделяемыми между процессами, сохраняя тем самым, драгоценную память данных, но и исчезают возможные проблемы безопасности, возникающие из-за перезаписывания значений, из-за которого программа может сделать что-нибудь нехорошее.
Предыдущий раздел: | Следующий раздел: | |
Назад | Оглавление | Вперед |