オリジナルポスターはこちら。私は問題に対する実用的な解決策があることを言及することを怠りました、それは私が望んでいたほど頑強ではありません。動揺しないでください。このコメントと回答のリクエストに参加しているすべての人に感謝します。「手順」in question
はvariadic
本質的にあり、63個以下の匿名のchar *
引数を期待します。
内容:複数の文字列の連結子。それは多くの議論を扱うことができますが、私は開発者に20以上を渡すことを勧めます。開発者がプロシージャを直接呼び出すことはありません。代わりに、「プロシージャ名」と呼ばれるマクロが、末尾のnullポインタとともに引数を渡すので、統計収集の終わりにいつ到達したかがわかります。
関数が2つの引数のみを受け取る場合は、最初の引数のコピーを作成し、そのポインターを返します。これは文字列リテラルの場合です。しかし、実際に行っているのはマスキングだけですstrdup
単一の有効な引数テストに失敗するrealloc
とmemcpy
、各ポインターとそのポインターを含む64レコードの静的データベースからのレコード情報を使用して、戻り値のコピーとして開始されstrlen
たセカンダリポインター()にmemcopyのサイズを追加するたびにに進みます。 memcpy
destination
reallocからの値。
最初の引数が動的ではないため、動的引数が必要であり、そのマクロが次のコードを使用して動的引数を実際のプロシージャ呼び出しに挿入することを示すために、「d」の付加を付けた2番目のマクロを作成しました。最初の引数:
strdup("")
これは、再割り当てできる有効なメモリブロックです。0を返すため、ループがそのstrlen
サイズをレコードに追加しても、何の影響もありません。ヌルターミネータは。で上書きされ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_ */
クレジットで私に言及するのはやめましょう。彼女は元気でダンディです。