6

引数として指定されたポインターを新しいサイズに再割り当てする関数があります。さて、問題は、マニュアルページによると、以前reallocに返されたポインタが必要なことです。malloccalloc

呼び出し元がこれらの要件を満たすポインターを渡すことを確認するにはどうすればよいですか? そうするための組み込みの C メカニズム (型修飾子など) はないようです。

さて、API を再構築する前に (現在の関数は十分に堅牢ではないと考えているため)、何かを見逃していないことを確認していただけますか?

前もって感謝します。

編集: 1 つの解決策は明らかに関数内で mallocすることです。それに関する問題は、呼び出し元が割り当てを「見ない」ことです。したがって、ドキュメントで明示的に、ポインターを解放する必要があると言う必要があります。これは、malloc されたポインターを提供することを期待するよりもさらに悪いことです (これは、呼び出し元がポインターを解放する必要があることを意味します)。

私が本当に欲しいのは、コンパイル時に悪用をブロックするものです。それとポニー。;-)

4

11 に答える 11

10

呼び出し元がこれらの要件を満たすポインターを渡すことを確認するにはどうすればよいですか?

ドキュメンテーション。

API を定義します。

呼び出し元を書いている人が API に従うことを拒否した場合、物事はクラッシュします。彼らはあなたのルールに従うことを拒否し、事態は崩壊しました。彼らは何を期待していましたか?

于 2010-07-23T14:07:13.000 に答える
4

結局のところ、C のポインターは機械語に過ぎず、malloc によって割り当てられる場合と割り当てられない場合があるプロセスのメモリ内のデータを指している場合と指していない場合があります。どのポインタにもそのような情報は添付されていません。

API に大きな警告を追加するだけです。ドキュメントに「malloc されていないこの関数ポインタを決して渡さないでください」と明確に記載されているにもかかわらず、誰かがそれを実行してバグやクラッシュが発生した場合、それはあなたのせいではありません。ここで防御的にプログラミングする方法はありません。

于 2010-07-23T14:12:47.620 に答える
2

考えられる方法の 1 つ。それを抽象化します。

foo.c
#include "foo.h"
struct foo{
   ...
} ;

foo *newFoo(...)          
void resize(foo *f)      

foo.h

struct foo;
typedef struct foo;

caller.c

foo *myfoo;
myfoo = newFoo(..)
resize(myfoo);
于 2010-07-23T14:41:42.920 に答える
2

そもそも、ユーザーはこの malloc されたポインターをどのように取得すればよいのでしょうか? API の別の関数によって取得される可能性はありませんか? それ以外の場合は、関数を呼び出す前に malloc でメモリのチャンクを割り当てる必要がある定型コードのように思えます。

あなたの状況では、私はそれを試してみます。私が提供する関数を介して呼び出し元に有効なポインターを取得させ、別の関数を介してそれを解放します。さらに良いことに、不透明な構造ですべてを包み込みます。

my_param_type my_param = init_param(....);
...
my_function_that_wants_malloc(.....,my_param);
...
free_param(my_param);

それはあなたのAPIで意味がありますか?

独自の型を持つことは、予想される init_param() 関数を介して取得しなければならないことを最も不自由なユーザーにとっても明らかです。

于 2010-07-23T15:18:30.347 に答える
2

ポインターが指している領域が[m|c]alloc();'d' されているかどうかを判断することはできません。API を定義して、API ユーザーがそれに従うことを期待することしかできません。

自分自身 (呼び出し先) にメモリを割り当てるのは法外ですか? realloc(NULL, size);それに拘束されている場合でも、初期割り当てを行うことができます。

あなたの問題に関するより多くの情報があればいいでしょう。

于 2010-07-23T14:10:02.727 に答える
0

Create a custom data type that is a renamed void pointer.

typedef void* myPointerType;

Write an allocate function (that can be a simple wrapper around malloc) that the user must use to allocate memory.

myPointerType myAllocateFunction (size_t size) {
    return (myPointerType)(malloc(size));
}

You would also want to make a matching "free" function.

Now, have your function (the one that performs the realloc) take a myPointerType object as a parameter instead of a generic pointer. You can cast it back down to a void* to use with realloc. To get around this, the user would have to manually cast a non-malloced pointer to a myPointerType, but you can specify in your documentation that casting to and from myPointerType is not allowed (so if they do this and their app crashes, it's because they misused the API).

There are even stronger ways that you can enforce this, but I'm not sure if it would be worth the trouble. You can't completely fool-proof an API (you'd be amazed at how capable fools are these days). Whatever you end up implementing, the best way to ensure that your API is used correctly is to provide clear, comprehensive documentation.

You're on your own for the pony, sorry.

于 2010-07-23T15:50:31.103 に答える
0

したがって、私はドキュメントで彼がポインタを解放しなければならないと明示的に言う必要があります。これは、mallocされたポインターを提供することを期待するよりもさらに悪いです(これは、呼び出し元がそれを解放する必要があることを意味します)。

Cライブラリでは、これは一般的な方法です。

于 2010-07-23T16:19:54.647 に答える
0

コンパイル時のチェックを探している場合、実際にできることは、「承認された」割り当て呼び出しによって返される新しい型を宣言することだけです。私は次のようなものを提案します:

typedef struct MEM_INFO {void *ptr; int 割り当て; struct *privateMemInfo priv;} ALLOCMEM[0];

privateMemInfo は、ヘッダーではなく .c ファイルで定義されるため、ファイル内のフィールドがいたずらからある程度保護されます。ALLOCMEM は配列型であるため、ptr と allocsize は常にドットではなく矢印演算子を使用してアクセスされることに注意してください。ALLOCMEM をパラメーターとして受け取るルーチンには、当然 ALLOCMEM へのポインターが与えられ、再配置を「適切に」実行できるようになります。したがって、たとえば、次のように使用します。

  ALLOCMEM foo = {0};
  if (reallocate(foo,12345) >= 0) /* うまくいきました */
于 2010-07-23T15:54:12.587 に答える
0

realloc を使用しないように実装を変更します。渡されたバッファーが小さすぎる場合は、新しい大きなバッファーを malloc し、渡されたバッファーの内容をそれに memcpy します。これにより、パフォーマンスがわずかに低下しますが、API の使いやすさが向上します。

于 2010-07-23T14:40:44.383 に答える
0

ポインター値しかない場合、そのポインター値が によって返されたかどうかを判断する (標準的な) 方法はありませんmalloc()。動的メモリ割り当てがプラットフォームでどのように機能するかについて深く詳しい知識がある場合は、ポインター値に基づいて知識に基づいた推測を行うことができますが、それでも実際に戻り値であったものを見ているという保証はありませんmalloc()。それから値をオフセットします (例: *ptr = malloc(10); foo(&ptr[5]);)。

努力する価値があるかもしれないし、そうでないかもしれない 1 つの戦略 (IME ではありません) は、割り当てられたポインターとサイズを追跡するある種のメモリ マネージャーの背後malloc()に 、realloc()、およびを隠すことです。free()を呼び出す代わりにrealloc()、コードでメモリ マネージャーのサイズ変更関数を呼び出します。これは、渡されたポインターがマネージ ポインターのリストにない場合にエラー コードを返します。

于 2010-07-23T14:52:27.890 に答える
0

関数内で静的ポインターを保持し、自分で realloc を呼び出すことができます。静的ポインタを返します。このようにして、ユーザーは割り当てや解放について心配する必要がありません。プロセスが終了すると、変数は自動的に解放されます。

realloc が失敗した場合、null ポインターが返されますが、元の malloc されたメモリはそのまま残されることに注意してください。これはメモリ リークの一般的な原因です。

于 2010-07-23T14:12:07.963 に答える