Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Общие вопросы > Как сравнить типы (структуры)?


Автор: mephistotel77 20.5.2010, 16:04
Добрый день. Есть такой код: СИшный
test_sev.h
Код

typedef struct _valcfg
{
   const char *name; // Имя параметра
   const char *value; // Значение параметра
   const char *opttype; // Тип параметра
} valcfg;

typedef struct _config
{
   valcfg *cmd;      // Команда
   valcfg *cnffile;   // Путь к конфигу
   stack *ipstack;  // Указатель на список структур, содержащих IP-адреса 
   valcfg *genport; // Порт для адресов
} config;

typedef struct _stack
{
   ipconfig *val; // Указатель на структуру
   stack *next;  //Указатель на след.элемент
} stack;

typedef _ipconfig
{
   const char *ipaddr; // Указатель на строку, содерж. IP
   const char *ipport;  // Указатель на строку, содерж. порт
} ipconfig;
valcfg* findvalcfg(config *cfg, char *val); 

Необходимо реализовать функцию findvalcfg,  которая на вход принимает строку val и конфиг, в котором надо искать. 
Естественно, что логика такая:
Пройтись по всех указателям, если указатель указывает на тип valcfg, то 
Код

if (cfg->valcfg.value == val)
{
   // Что-то делаем
}

если указывает на что-то другое (на ipconfig), то пропускаем.
Как это можно реализовать? А точнее, как мне узнать на какой типа указывает указатель и как сравнить два типа, чтобы узнать что это нужный тип valcfg, а не ipconfig.
PS:
Для лучшего понимания объясню предысторию. Хочется "умно" разбирать опции командой строки.
1. Перемена мест опции не влияла на выполнение программ (а с getopt это не так)
2. Учитывался приоритет:
   а) приоритет у опций командной строки наивысший
   б) опции, взятые из файла не могут перезатирать опции командной строки, но могут затирать встроенные в программу опции (забитые в коде)
   в) опции, забитые в коде имеют низший приоритет
И хочется делать, например, так:
test -i 192.168.1.1:8080 192.169.2.2 192.168.1.3:1835 192.168.2.4 -p 9999
где -i - IP-адреса в формате [IP-адрес] или [IP-адрес:порт]
       -p - порт, применяется только для тех IP-шников, у которых не задан IP
Таким образом у 192.169.2.2 и 192.168.2.4 будет порт 9999.
Проблема возникает, когда мы получаем опции из файла в формате <имя_перем> <значение> 
(например ipaddr 192.168.3.4). Т.к. строку ipaddr надо сравнить с полями value, для этого нужно пробежаться по структуре config.

Автор: djamshud 20.5.2010, 16:53
Если си, в начало каждой структуры можно положить инт - значение типа.
Код

enum {IFCONFIG,SYSCONFIG,BLABLABLA,...};

struct ifconfig{
int type;
...
};

...

struct ifconfig ifconfig={IFCONFIG,...};
struct sysconfig sysconfig={SYSCONFIG,...};


В плюсах можно много проще: базовый класс конфиг, от него наследники. Проверка на тип:
Код

if(dynamic_cast<ifconfig*>(conf_object)!=0){that is ifconfig struct;}

Автор: mephistotel77 20.5.2010, 17:18
Т.е. я правильное понял, что вы предлагаете сделать что-то вроде:
Код

config *cfg;
while (((*cfg)++) != NULL) // Кстати... эта строчка сработает? 
                                   // Можно перемещаться по структуре, содер. разные типы|структуры в теле, через указатель?
{
   if (*cfg.type == VALCFG)
   {
   
   }
   // если if (*cfg.cmd) или if (*cfg.genport) - то значит мы уже знаем тип, раз получаем его поле. 
   //
}

Верно? А нет каких-то способов попроще?
И если есть предложения по изменению самих структур... может стоит  переписать базовые структуры, 
с удовольствием выслушаю мнения по этому поводу, чтобы не делать таких "хуков".

Автор: djamshud 20.5.2010, 17:33
>с удовольствием выслушаю мнения по этому поводу, чтобы не делать таких "хуков".

Я честно говоря вообще не очень понял, зачем так сложно разбирать argv. То есть, зачем - понял, почему так - нет. На все флаги легко можно среагировать и одним простым проходом по аргументам. Когда-то я писал это, найду - выложу.

>Кстати... эта строчка сработает?

Что такое config *cfg не понятно... Если это буфер, куда друг за дружкой вкатаны структуры, то нет. Нужно читать первые четыре байта, опрелять тип и привести текущий кусок с нему, дальше уже и работать. Потом опять вытаскивать тип и т.д., пока не пройдетесь по всему буферу. Но эта задача для вас, как я понимаю, будет весьма сложна. Лучше перепроектирвать.

>Можно перемещаться по структуре, содер. разные типы|структуры в теле, через указатель?

Можно, но проще привести "непонятный указатель" к указателю на конкретную структуру, а дальше работать с обычными полями.

Автор: mephistotel77 20.5.2010, 17:55
Что такое 
Код
config *cfg
 описано в коде в первом сообщении:
Код

typedef struct _config
{
   valcfg *cmd;      // Команда
   valcfg *cnffile;   // Путь к конфигу
   stack *ipstack;  // Указатель на список структур, содержащих IP-адреса 
   valcfg *genport; // Порт для адресов
} config;

В структуре забиты указатели на те опции, которые есть у программы и которые разбираются. 
cfg - это указатель на структуру, которая содержит все конфигурационные параметры (аргументы программы и т.п.). Т.е. фактически 
это список указателей на структуры. 
Так можно (*cfg)++ сделать? 
Просто cfg++ как я понял просто перепрыгнет на след. такую структуру, которой на самом деле нет.

Она заполняется не только из командной строки, но также и из файла, если указать опцию -f. 

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

Автор: djamshud 20.5.2010, 19:56
>Просто cfg++ как я понял просто перепрыгнет на след. такую структуру, которой на самом деле нет.

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

Код

struct base{
int type;
};

struct ipconfig{
int type;
char *....
....
};


Потом создается массив указателей на base, в который на самом деле вносят указатели на нужные структуры. Ну а дальше все просто: проходимся по массиву, смотрим тип, приводим указатель к нужной структуре и вуаля.

Автор: KOHCEPBATOP 20.5.2010, 20:50
Цитата(djamshud @  20.5.2010,  19:56 Найти цитируемый пост)
struct base{
int type;
};


Можно еще так
Код

struct base{
   int type; // тип структуры
   int size; // размер структуры
};

Тогда реализовать переход к следующему экземпляру будет проще.

Код

char * ptr = (char*)...;
while(1)
   {
   base * pbase = (base *)ptr;
   if (pbase->type == ENDCFG) // последний элемент
      {
          break;
      };
   switch(pbase->type )      {
   case VALCFG:
      {
         valcfg * pvalcfg = (valcfg*)ptr;
         ........
      };
       break;
   case STACKCFG:
      {
         stackcfg * pstackcfg = (stackcfg*)ptr;
         ........
      };
      break;
   };
   ptr += pbase->size; // перемещаемся на следующую структуру
};


Автор: mephistotel77 24.5.2010, 10:04
Спасибо большое. М-да... сразу понимаешь все прелести ООП=)) На C такие извраты получаются...=((
Тему пока не закрываю, пока буду допиливать прогу, может кто (или сам) что дополнит. 

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)