pokk
Помогающий
Offline
|
|
« : 25-01-2016 10:04 » |
|
Добрый день, подскажите какие функции должны использоваться, что бы можно было сформировать такую строку ключ значене. { "orderID": 12345, "shopperName": "Ваня Иванов", "shopperEmail": "ivanov@example.com", "contents": [ { "productID": 34, "productName": "Супер товар", "quantity": 1 }, { "productID": 56, "productName": "Чудо товар", "quantity": 3 } ], "orderCompleted": true } Я частично создал велосипед для формирования ключ значения и он меня более менее устраивает, но как дошёл до массива тут всё если в ручную ещё хоть что-то получается,а при проходе циклом уже нет всё разваливается(непонятно когда надо закрывать его). Вот хотелось бы по смотреть как это делают по фэншую.
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #1 : 25-01-2016 10:53 » |
|
Код с циклом в студию. Без этого непонятно, где сложность возникает.
|
|
|
Записан
|
|
|
|
pokk
Помогающий
Offline
|
|
« Ответ #2 : 25-01-2016 12:13 » |
|
Сейчас нету доступа к коду с циклом, но примерно у меня такой колхоз. index=MakeStr_int(buf,index,"Pout:",',',THttpPageConfing.Pout); index=MakeStr_text(buf,index,"NameOfTheUnit:",',',THttpPageConfing.NameOfTheUnit); index=MakeStr_text(buf,index,"IP:",',',THttpPageConfing.IP); *file_len+=MakeStr_text(buf,index,"SerNumber:",',',THttpPageConfing.SerNumber); Не большая проблема возникает с определением места постановки "]," но это всё из за того что добавление новой пары ключ значение сделано через ж, а как правильно не могу придумать.
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #3 : 25-01-2016 12:58 » |
|
pokk, какой смысл несёт index - текущее место в буфере? Задачу формирования строки можно разбить на составляющие примерно так (на глаз и без учёта обработки ошибок и проверки границ): char * itemToStr(char * buf, const ItemType * item) { buf += sprintf(buf, "\"%s:\"", item->name); if (typeof(item->value) == /*атомарный тип*/) { buf += sprintf(buf, "%format", item->value); } else{ // массив: *buf++ = '['; for (/*перебираем элементы item->value*/) { buf = itemToStr(buf, subitem); // добавляем разделитель по необходимости } *buf++ = ']'; } return buf; }
плюс для словаря вставить аналогичное массиву, или я что-то упустил? Вроде бы, можно сделать попроще, если поступиться эффективностью и под каждый элемент отдельную строку создавать.
|
|
« Последнее редактирование: 25-01-2016 13:03 от Вад »
|
Записан
|
|
|
|
pokk
Помогающий
Offline
|
|
« Ответ #4 : 25-01-2016 14:14 » |
|
itemToStr рекурсивная функция? Я что-то похожее начинал делать но не допёр как быть с разным форматом Value, теперь вроде понял что надо всё в строку переводить а потом добавлять(я пытался сразу два действия делать). По этому меня интересуют вот эти моменты Что за типа и что он там ещё содержит или может содержать кроме value И if (typeof(item->value) == /*атомарный тип*/) { buf += sprintf(buf, "%format", item->value); } Это как-то совсем не понятно для чего. плюс для словаря вставить аналогичное массиву, или я что-то упустил? Вроде бы, можно сделать попроще, если поступиться эффективностью и под каждый элемент отдельную строку создавать Тоже не понятно =((
|
|
|
Записан
|
|
|
|
RXL
|
|
« Ответ #5 : 25-01-2016 14:47 » |
|
По моему нужно исходить из формата: 1) фиксированный формат или формат неизвестен? 2) нафига нам неизвестный формат?
Два простых ответа решают большую часть проблем разработки данной фичи.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
pokk
Помогающий
Offline
|
|
« Ответ #6 : 25-01-2016 15:00 » |
|
Формат чего? Значений? То его несколько: 1) Текст 2) char,Int 3) IP(массив из 4х байт)
|
|
|
Записан
|
|
|
|
Вад
|
|
« Ответ #7 : 25-01-2016 21:11 » |
|
itemToStr рекурсивная функция?
да, но это не так важно, важен принцип: "если одно - делаем так, если другое - оборачиваем в скобки, в середине делаем цикл, внутри цикла сводим задачу к предыдущей" (в качестве решения первой задачи можно ведь и вашими MakeStr_int/MakeStr_text пользоваться). Что за типа и что он там ещё содержит или может содержать кроме value тут универсальный тип может быть (мы ведь про язык Си), я себе представил что-то вроде typedef struct { char * name; int type; void * value; } ItemType;
- ну, может, void * на union можно заменить, содержащий int/void* Это всё тоже не особо важно, просто был вопрос про "как бы стали делать" — я бы стал как-то так (но я на Си почти не пишу, может, кто и лучше предложит). Соответственно, на деле там был бы switch по значению type (например, INT/DOUBLE/STR/ARRAY/DICT), и у каждого свой формат (атомарные типы через sprintf выводятся напрямую, остальные два -- как и сказал, отдельный случай с циклом). плюс для словаря вставить аналогичное массиву, или я что-то упустил? Вроде бы, можно сделать попроще, если поступиться эффективностью и под каждый элемент отдельную строку создавать Тоже не понятно =(( Встречное непонимание, уточните вопрос. Вообще, согласен с RXL, если там пару типов значений сбросить надо (int, char* и один тип структур в массиве), то можно забыть про универсальные типы, но тогда и ничего сложного в том, чтобы сделать запись массива. Не смотрите на конкретную реализацию, ищите идеи декомпозиции вашей задачи.
|
|
« Последнее редактирование: 25-01-2016 21:15 от Вад »
|
Записан
|
|
|
|
RXL
|
|
« Ответ #8 : 25-01-2016 21:12 » |
|
Нет-нет, разбивать на молекулы и атомы не надо. Я имел в виду структуру данных. Зачем хранить и обрабатывать данные, которые тебе не нужны? Например, программа ждет {"a": <int>, "b": <string>}, а приходит {"a": <int>, "b": <string>, "c": <float>, "d: [1,2], "f": {"g": <string>}}. Поля c, d, e, f и g программа может смело игнорировать. Парсеру нужно пройти все поля, но сохранять ненужные необходимости нет.
Кстати, откуда такое жесткое ограничение - Си? C++ куда удобнее для работы с динамическими коллекциями.
|
|
« Последнее редактирование: 25-01-2016 21:16 от RXL »
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
pokk
Помогающий
Offline
|
|
« Ответ #9 : 26-01-2016 02:44 » |
|
Благодарю всех помощь, решил остановится примерно на таком варианте (помог универсальный тип ItemType) Тут все ключи собраны воедино, и при отправке надо только заполнить Value и указать какие данные выдавать (после Access). Хотя ещё подумываю добавить в структуру сразу адреса переменных Value, тогда перед отправкой нечего заполнять не надо будет прост разрешить какие данные отправляются. PS: Остался не большой вопрос когда ставить разделители в начале функции itemToStr или после добавления строки, но в любом случае этот разделить вылезит или в начале всей строки или в конце. Так что решил поставить его в конце строки а после заполнения всех пунктов заменить на "/0". enum{ NAME_ITEM1, NAME_ITEM2, MAX_ITEM, }
ItemType Item[MAX_ITEM]={ .Item[NAME_ITEM1]={ .Type=INT, .KEY="KEY1:", .Access=0, }, .Item[NAME_ITEM2]={ .Type=Str, .KEY="KEY2:", .Access=0, }, } //---------------------------------------------------------- Item[NAME_ITEM1].access=1; //Разрешено Item[NAME_ITEM1].access=1; //Разрешено Item[NAME_ITEM1].value.int16=123; Item[NAME_ITEM2].value.STR="TEST1"; //адрес строки Item[NAME_ITEM3].value.ip=IP; //адрес строки Item[NAME_ITEM3].value.mac=mac; //адрес строки Item[NAME_ITEM4].value.char8=123;
Item[NAME_ITEM5].array.str[]="str1","str2",...;
Item[NAME_ITEM6].array.int16[]=1,2,3,4,...;
for(i=0;i<MAX_INTEM;i++){ itemToStr(Buff,Item[i]); } где, itemToStr char * itemToStr(unsigned char index,char * buf, const ItemType * item) { index += sprintf(buf, "\"%s:\"", item->name); switch(item->type){ //--------------------------------------------------- case ARRAY:{ // массив: break; } //--------------------------------------------------- case INT16:{ //перевод числа в строку(+ копирование) // break; } case STR:{ //Копирование строки с адреса item->str break; } //--------------------------------------------------- } return index; }
Кстати, откуда такое жесткое ограничение - Си? C++ куда удобнее для работы с динамическими коллекциями. Пишу программу для микроконтроллера, хоть там и есть поддержка С++, но я с ним не работал так что ещё рано для меня.
|
|
|
Записан
|
|
|
|
Dale
|
|
« Ответ #10 : 26-01-2016 08:26 » |
|
Пишу программу для микроконтроллера Тогда позволю себе совет: для микроконтроллера следует писать на порядок аккуратнее, чем это обычно делается на ПК, а если микроконтроллер еще и без операционной системы - то на два порядка. По возможности проверить код на совместимость с требованиями MISRA (тут аккуратнее, без фанатизма, ибо часть из них явно устарели), прогнать через статический анализатор (например, lint или его клон) и устранить все его предупреждения. Например, в функции itemToStr нарушено обязательное правило 15.3 MISRA 2004, которое лично я считаю весьма полезным: Rule 15.3 (required): The final clause of a switch statement shall be the default clause.
The requirement for a final default clause is defensive programming. This clause shall either take appropriate action or contain a suitable comment as to why no action is taken.
Ну и, разумеется, с void * следует быть поакккуратнее и не использовать без совершенно крайней необходимости, которая реально наступает крайне редко. Не такая уж это безобидная конструкция.
|
|
|
Записан
|
Всего лишь неделя кодирования с последующей неделей отладки могут сэкономить целый час, потраченный на планирование программы. - Дж. Коплин.
Ходить по воде и разрабатывать программное обеспечение по спецификациям очень просто, когда и то, и другое заморожено. - Edward V. Berard
Любые проблемы в информатике решаются добавлением еще одного уровня косвенности – кроме, разумеется, проблемы переизбытка уровней косвенности. — Дэвид Уилер.
|
|
|
RXL
|
|
« Ответ #11 : 26-01-2016 09:34 » |
|
С JSON есть еще засада. Например, ждем {"a": <int>, "b": <string>}, а приходит {"a": <string>, "b": <string>}. JSON это допускает. И динамические языки легко переводят int <-> string, а жестко типизированным языкам приходится выбирать: либо делать принудительную конверсию (т.е. надо заранее знать, какой должен быть тип поля), либо считать такие данные невалидными.
|
|
|
Записан
|
... мы преодолеваем эту трудность без синтеза распределенных прототипов. (с) Жуков М.С.
|
|
|
|