Как инициализировать программу на C, используя файл, окружение и / или командную строку? - PullRequest
5 голосов
/ 08 мая 2009

В C, как настроить начальные параметры для некоторой программы, используя пары ключ-значение, с любым или со всеми: простой текст файл конфигурации , переменные среды и параметры в командной строке. Кроме того, как решить, какие значения метода переопределяют значения двух других. Затем, если значения были изменены, необязательно обновить файл конфигурации.

Какой самый простой способ сделать это, и что, если таковые имеются, являются наиболее приемлемыми методами? Существует ли, желательно небольшая, программа с открытым исходным кодом, которая дает хороший пример того, как это можно сделать?

Ответы [ 6 ]

5 голосов
/ 08 мая 2009

Эрик Рэймонд рассматривает многое из этого в Разделе 10 Искусство программирования Unix Очевидно, что это ориентировано на Unix, но большинство принципов могут применяться в любой ОС.

5 голосов
/ 08 мая 2009

Основы:

  • Для настройки вашей программы с использованием переменных среды вы можете использовать функцию getenv, определенную в stdlib.h.
  • Чтобы сконфигурировать вашу программу, используя аргументы командной строки, объявите вашу основную функцию как 'int main (int argc, const char * const * argv)' и используйте цикл, чтобы просмотреть аргументы в массиве argv. Размер указан в argc.
  • Чтобы настроить вашу программу с помощью файла конфигурации, желательно выбрать какую-нибудь библиотеку, делающую это для вас, вместо того, чтобы придумывать еще один пользовательский формат файла конфигурации. Обратите внимание, что в зависимости от платформы, на которую вы ориентируетесь, существуют также библиотеки для анализа аргументов командной строки.

Какой источник настроек должен перекрывать друг друга, зависит от приложения, но, на мой взгляд, в большинстве случаев аргумент командной строки> переменная среды> файл конфигурации имеет смысл.

Вот пример получения конфигурации из среды и командной строки с переопределением среды командной строки:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, const char* const* argv) {
    int i;
    const char* myConfigVar;

    // get default setting from environment
    myConfigVar = getenv("MY_CONFIG_VAR");

    // if the variable wasn't defined, initialize to hardcoded default
    if (!myConfigVar)
        myConfigVar = "default value";

    // parse commandline arguments
    // start at 1, because argv[0] contains the name of the program
    for (i = 1; i < argc; ++i) {
        if (strcmp("--my-config-var", argv[i]) == 0) {
            if (i + 1 < argc)
                myConfigVar = argv[i + 1];
            else
                printf("missing value for my-config-var argument\n");
        }
    }

    printf("myConfigVar = '%s'\n", myConfigVar);
    return 0;
}

Вы уже видите, что это очень долго и утомительно очень скоро, поэтому лучше использовать существующую библиотеку, если она существует для вашей желаемой целевой платформы (платформ), или, по крайней мере, разделить этот вид кода на ряд функций.

Другой интересный вариант - привязать язык сценариев к вашему приложению, тогда вы можете заставить свое приложение только читать и «выполнять» файл настроек, а пользователь может настроить файл настроек для чтения некоторых настроек из среды, а некоторых из командная строка, например. Это действительно зависит от типа и размера приложения и вашей целевой аудитории, стоит ли это делать.

2 голосов
/ 08 мая 2009

Вопрос не очень понятен. Является ли вопрос «какие механизмы существуют?», «Каковы соглашения для аргументов и форматов?» Или «как вы должны смешивать и сопоставлять?»?

Есть несколько довольно стандартных способов (по крайней мере, в мире Unix):

  • переменные окружения
  • конфигурационные файлы
  • аргументы командной строки
  • как подмножество вышеупомянутых конфигурационных файлов, указанных в командной строке

Чтобы выбрать, какие методы использовать для своей собственной программы, изучите множество программ из канона принятой практики, прежде чем заморозить свой собственный выбор, прочитайте несколько блогов, прочитайте несколько книг ...

Файлы конфигурации, вероятно, являются наиболее переносимыми в операционных системах.

Лечение может быть довольно сложным. Если аргументы командной строки могут повлиять на интерпретацию файлов конфигурации или переменной среды, но вы все же хотите, чтобы командная строка отменяла другие механизмы (хорошая идея), вам может потребоваться три прохода:

  1. Разбор командной строки и установка любых переменных, которые влияют на дальнейшие настройки (скажем, какой файл конфигурации нужно прочитать)
  2. Обработка файлов конфигурации и переменных среды (в каком порядке?)
  3. Перезапустите командную строку, чтобы переопределить все остальные настройки.

В традиции Unix посмотрите на getopt и getopt_long. Также рассмотрите инструменты как gengetopt

Вы можете упростить проблему с конфигурационным файлом, создав для них сценарии оболочки, которые устанавливают переменные среды (но это блокирует вас в модели Unix). Разбор простого текста прост и кроссплатформенен, но позволяет писать больше кода. Использование стандартного формата и библиотеки предъявляет требования к среде сборки вашего пользователя, но должно экономить на ошибках и путанице.


Если ваша среда конфигурации сложна, очень полезно инкапсулировать состояние конфигурации в структуру, которую можно передавать по мере необходимости. Это подход, принятый gengetopt, и я нашел его полезным.

2 голосов
/ 08 мая 2009

Существует множество библиотек для разбора файла конфигурации для различных форматов. Ищите форматы XML и INI, для двух популярных вариантов. Написание нестандартного парсера, вероятно, плохая идея, так как может потребоваться много работы для получения небольшого выигрыша или вообще без него. Здесь - это случайная библиотека C для анализа INI-файлов, XML оставлен в качестве упражнения.

Приоритет между настройками обычно таков, что параметры командной строки переопределяют любые «окружающие» настройки. Я бы предложил такие приоритеты в порядке убывания важности:

  1. Параметры командной строки переопределяют что-либо
  2. Файл настроек следующий
    • Иногда разделяется между локальными и системными глобальными файлами пользователя
  3. Следующие переменные среды

Но 2 и 3 вполне могут быть перевернуты.

1 голос
/ 09 мая 2009

Язык Lua частично получил свое начало из-за необходимости иметь четко определенный язык конфигурации для набора инструментов. Все еще довольно легко интегрировать Lua в качестве языка конфигурации. Довольно полный пример приведен в книге «Программирование на Lua», старшее издание которой доступно в Интернете. Глава 25 описывает использование Lua C API для встраивания Lua в качестве языка конфигурации и причины, по которым вы можете захотеть это сделать.

1 голос
/ 08 мая 2009

Для Unix-подобных шаблонов проектирования в этой области, посмотрите на "100 * * Art of Unix Programming Рэймонда". В нем обсуждается расстановка приоритетов аргументов командной строки над переменными среды и файлами конфигурации и т. Д.

...