оригинальный постер здесь. Я забыл упомянуть, что у меня есть рабочее решение проблемы, оно не такое надежное, как я надеялся. Пожалуйста, не расстраивайтесь, я ценю всех, кто принял участие в этом запросе комментариев и ответов. «Процедура» in question
по своей природе является variadic
и предполагает не более 63 анонимных char *
аргументов.
Что это такое: конкатенатор нескольких строк. Он может обрабатывать множество аргументов, но я советую разработчику не передавать более 20 или около того. Разработчик никогда не вызывает процедуру напрямую. Вместо этого макрос, известный как «имя процедуры», передает аргументы вместе с конечным нулевым указателем, поэтому я знаю, когда я встретил конец сбора статистики.
Если функция получает только два аргумента, я создаю копию первого аргумента и возвращаю этот указатель. Это строковый литерал. Но на самом деле все, что он делает, это маскирует strdup
Не пройдя проверку единственного допустимого аргумента, мы переходим к realloc
и memcpy
, используя информацию о записи из статической базы данных из 64 записей, содержащих каждый указатель и его strlen
, каждый раз добавляя размер memcopy к вторичному указателю (memcpy
destination
), который начинался как копия возвращаемого значения из realloc.
Я написал второй макрос с придатком «d», чтобы указать, что первый аргумент не является динамическим, поэтому требуется динамический аргумент, и этот макрос использует следующий код для внедрения динамического аргумента в фактический вызов процедуры как первый аргумент:
strdup("")
Это действительный блок памяти, который можно перераспределить. Его strlen
возвращает 0, поэтому, когда цикл добавляет его размер к записям, он ни на что не влияет. Нулевой терминатор будет перезаписан на memcpy
. Работает чертовски хорошо, надо сказать. Однако, будучи новичком в C всего за последние несколько недель, я не понимал, что вы не можете «защитить от дурака» этот материал. Я полагаю, люди следуют указаниям или попадают в ад DLL.
Код отлично работает без всех этих дополнительных махинаций и свистков, но без способа возвратно-поступательного движения одного блока памяти процедура теряется при обработке цикла из-за всего управления динамическими указателями. вовлеченный. Поэтому первый аргумент всегда должен быть динамическим. Я где-то читал, что кто-то предложил использовать переменную c-static, содержащую указатель в функции, но тогда вы не можете использовать эту процедуру, чтобы делать другие вещи в других функциях, например, что было бы необходимо в синтаксическом анализаторе рекурсивного спуска, который решил скомпилировать струны по ходу дела.
Если вы хотите увидеть код, просто спросите!
Удачного кодирования!
mkstr.cpp
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
struct mkstr_record {
size_t size;
void *location;
};
// use the mkstr macro (in mkstr.h) to call this procedure.
// The first argument to mkstr MUST BE dynamically allocated. i.e.: by malloc(),
// or strdup(), unless that argument is the sole argument to mkstr. Calling mkstr()
// with a single argument is functionally equivalent to calling strdup() on the same
// address.
char *mkstr_(char *source, ...) {
va_list args;
size_t length = 0, item = 0;
mkstr_record list[64]; /*
maximum of 64 input vectors. this goes beyond reason!
the result of this procedure is a string that CAN be
concatenated by THIS procedure, or further more reallocated!
We could probably count the arguments and initialize properly,
but this function shouldn't be used to concatenate more than 20
vectors per call. Unless you are just "asking for it".
In any case, develop a workaround. Thank yourself later.
*/// Argument Range Will Not Be Validated. Caller Beware!!!
va_start(args, source);
char *thisArg = source;
while (thisArg) {
// don't validate list bounds here.
// an if statement here is too costly for
// for the meager benefit it can provide.
length += list[item].size = strlen(thisArg);
list[item].location = thisArg;
thisArg = va_arg(args, char *);
item++;
}
va_end(args);
if (item == 1) return strdup(source); // single argument: fail-safe
length++; // final zero terminator index.
char *str = (char *) realloc(source, length);
if (!str) return str; // don't care. memory error. check your work.
thisArg = (str + list[0].size);
size_t count = item;
for (item = 1; item < count; item++) {
memcpy(thisArg, list[item].location, list[item].size);
thisArg += list[item].size;
}
*(thisArg) = '\0'; // terminate the string.
return str;
}
mkstr.h
#ifndef MKSTR_H_
#define MKSTR_H_
extern char *mkstr_(char *string, ...);
// This macro ensures that the final argument to "mkstr" is null.
// arguments: const char *, ...
// limitation: 63 variable arguments max.
// stipulation: caller must free returned pointer.
#define mkstr(str, args...) mkstr_(str, ##args, NULL)
#define mkstrd(str, args...) mkstr_(strdup(str), ##args, NULL)
/* calling mkstr with more than 64 arguments should produce a segmentation fault
* this is not a bug. it is intentional operation. The price of saving an in loop
* error check comes at the cost of writing code that looks good and works great.
*
* If you need a babysitter, find a new function [period]
*/
#endif /* MKSTR_H_ */
Не за что упоминать меня в титрах. Она в порядке и денди.
person
Community
schedule
11.04.2012