4

注: ここで「静的文字列」と言うときは、realloc で処理できないメモリを意味します。

こんにちは、私は char * 引数を取るプロシージャを作成しました。メモリが realloc を介して再配置可能/サイズ変更可能でない IF の複製を作成したいと考えています。そのままでは、手順は「重い」文字列プロセッサであるため、静的であるかどうかに関係なく、無知で文字列を複製すると、将来メモリのオーバーヘッド/処理の問題が確実に発生します。

例外ハンドラを使用して静的文字列を変更しようとしましたが、アプリケーションは予告なしに終了します。私は一歩下がって C を見て、「私は感心していません」と言います。私が聞いたことがあれば、それは例外です。

静的変数でreallocを呼び出すために例外ハンドラを使用しようとしました... Glibは、構造体への個人情報を見つけることができないと報告しています(私は確信しています)私は知りませんが、プログラムで明らかにabortを呼び出しますlongjmp/setjmp OR C++ try, catch finally でキャッチできる例外ではないことを意味します。

これを合理的に行う方法があるに違いないと確信しています。たとえば、動的メモリは静的メモリの近くに配置されていない可能性が最も高いため、アドレスからこの情報を漏らす方法があれば...ビンゴになるかもしれません..

C/C++ プリプロセッサに、マクロ引数のソースとタイプを識別できるマクロがあるかどうかはわかりませんが、そうでない場合はかなりばかげているでしょう。マクロ アセンブラは、そのようなことについてはかなり賢いです。堅牢なエラー処理の欠如から判断すると、そうでなくても少し驚かないでしょう。

4

5 に答える 5

5

C には、静的に割り当てられたメモリ ブロックと動的に割り当てられたメモリ ブロックを区別する移植可能な方法がありません。struct文字列ポインタと、オブジェクトが占有するメモリのタイプを示すフラグを使用して、独自のものを作成できます。C++ では、2 つの異なるコンストラクタ (メモリの種類ごとに 1 つ) を持つクラスにして、作業を楽にすることができます。

プログラムの中止に関する限り、動的に割り当てられていないメモリを解放または再割り当てしようとすることは未定義の動作であるため、中止は公正なゲームです。

于 2012-04-11T00:09:21.443 に答える
3

メモリの範囲を検出し、いくつかのポインター比較を実行できる場合があります。ポインタがスタック、ヒープ、またはその他の場所にあるかどうかを知る必要があるガベージ コレクション コードでこれを行いました。

mallocすべての割り当てを制御する場合は、 、callocまたはから出てきたすべての動的ポインターに基づいて最小境界と最大境界を維持するだけですrealloc。最小値よりも小さいか最大値よりも大きいポインターはおそらくヒープ内になく、このmin区切らmaxれた領域が静的領域と交差する可能性はほとんどありません。ポインターが静的であるか、malloc から取得されたものであることがわかっている場合、そのポインターは malloc されたストレージの「境界ボックス」の外にある場合、静的でなければなりません。

そのようなものが機能せず、C 標準では、正確な等値または不等値以外の関係演算子を使用した異なるオブジェクトへのポインターの比較に意味を与えない「ミュージアム」マシンがいくつかあります。

于 2012-04-11T00:08:26.603 に答える
2

得られるソリューションはプラットフォーム固有であるため、実行しているプラ​​ットフォームを指定することをお勧めします。

abort予期しないパラメーターを渡したときにライブラリが呼び出される理由については、実行を継続するよりも安全な傾向があります。確かに面倒ですが、その時点で、ライブラリは、それを呼び出しているコードが回復できない状態にあることを認識しています。

于 2012-04-11T00:07:54.350 に答える
1

char * 引数を取るプロシージャを作成しましたが、realloc を介してメモリが再配置可能/サイズ変更可能でない IF の複製を作成したいと考えています。

基本的に、問題は、操作しているスコープでは利用できない情報に基づいてメモリ管理を行いたいということです。明らかに、文字列を作成するときにスタック上にあるかヒープ上にあるかはわかりますが、その情報は関数内に入るまでに失われます。それを修正しようとすることはほぼ不可能であり、間違いなく標準の範囲外です。

例外ハンドラを使用して静的文字列を変更しようとしましたが、アプリケーションは予告なしに終了します。私は一歩下がって C を見て、「私は感心していません」と言います。私が聞いたことがあれば、それは例外です。

すでに述べたように、C には例外がありません。C++はこれを行うことができますが、C++ 標準委員会は、C 関数が C++ で異なる動作をすることは悪夢になると考えています。

これを合理的に行う方法があるに違いないと確信しています。

ucontext.hまたはWindows ファイバーを使用して作成した (そのため、アドレスの範囲を知っている) スタックでアプリケーションを既定のスタックに置き換え、アドレスがその範囲内にあるかどうかを確認することができます。ただし、(1) これは、ライブラリを使用するすべてのアプリケーションに大きな負担をかけます (もちろん、ライブラリを使用する唯一のアプリケーションを作成した場合は、その負担を喜んで受け入れることができます)。realloc(2)他の理由 (を使用しstaticて割り当て、カスタム アロケータを使用して割り当て、SysAllocWindowsHeapAllocを使用newして割り当て、C++ で使用して割り当てなど)で edできないメモリは検出されません。

代わりに、メモリの再割り当てに使用される関数を指す関数ポインターを関数に持たせることをお勧めします。関数ポインタが の場合NULL、メモリを複製します。それ以外の場合は、関数を呼び出します。

于 2012-04-11T00:23:09.913 に答える
0

オリジナルポスターはこちら。私は問題に対する実用的な解決策があることを言及することを怠りました、それは私が望んでいたほど頑強ではありません。動揺しないでください。このコメントと回答のリクエストに参加しているすべての人に感謝します。「手順」in questionvariadic本質的にあり、63個以下の匿名のchar *引数を期待します。

内容:複数の文字列の連結子。それは多くの議論を扱うことができますが、私は開発者に20以上を渡すことを勧めます。開発者がプロ​​シージャを直接呼び出すことはありません。代わりに、「プロシージャ名」と呼ばれるマクロが、末尾のnullポインタとともに引数を渡すので、統計収集の終わりにいつ到達したかがわかります。

関数が2つの引数のみを受け取る場合は、最初の引数のコピーを作成し、そのポインターを返します。これは文字列リテラルの場合です。しかし、実際に行っているのはマスキングだけですstrdup

単一の有効な引数テストに失敗するreallocmemcpy、各ポインターとそのポインターを含む64レコードの静的データベースからのレコード情報を使用して、戻り値のコピーとして開始されstrlenたセカンダリポインター()にmemcopyのサイズを追加するたびにに進みます。 memcpy destinationreallocからの値。

最初の引数が動的ではないため、動的引数が必要であり、そのマクロが次のコードを使用して動的引数を実際のプロシージャ呼び出しに挿入することを示すために、「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_ */

クレジットで私に言及するのはやめましょう。彼女は元気でダンディです。

于 2012-04-11T01:40:53.197 に答える