3
#include <stdio.h>

void swap(void *v[], int i, int j)
{
    void *tmp;

    tmp = v[i];
    v[i] = v[j];
    v[j] = tmp;
}

int main(void)
{
    char *s[] = {"one", "two"};
    printf("%s, %s\n", s[0], s[1]);
    swap(s, 0, 1);
    printf("%s, %s\n", s[0], s[1]);
    return 0;
}

出力:

one, two

two, one

警告: no compatible pointer casting, need void**, but char

このプログラムを使用してK&Rの swap 関数をシミュレートし、関数ポインターの使用方法を示しました。私の質問は、のキャストvoid pointerが常に安全かどうか、またはそれを置き換える方法があるかどうかです。

4

3 に答える 3

8

いいえ、(関数パラメータが実際に何であるか) が期待されるchar**場所に aを渡すことは必ずしも安全ではありません。コンパイラが明示的なキャストを実行させるという事実は、そのヒントです。void**void*[]

実際には、問題ない可能性が高いです。ただし、厳密に言えば、通常、sizeof (T*) == sizeof (U*)異なる型TU. (たとえば、sizeof (int*) < sizeof (char*)ポインターintがアラインされているため、最下位ビットを格納する必要がないという架空のシステムを想像できます。) その結果、swap関数がv間違ったオフセットを使用して配列にインデックスを付ける可能性があります。

また、comp.lang.c FAQ の Q4.9 も参照してください:仮パラメーター typevoid **を指定して、このようなことを行うことはできますか?

安全に呼び出すswapには、次のようにする必要があります。

void* temp[] = { &s[0], &s[1] };
swap(temp, 0, 1);

tempただし、 の要素ではなく の要素を交換しますs

をオーサリングしている場合swap、一般に、そのような関数はvoid*(1 ではなくvoid**)size_t引数と、各要素のサイズを指定する引数を取るようにする必要があります。次に、関数void*char*安全にキャストして、個々のバイトを交換できます。

void swap(void* p, size_t elementSize, size_t i, size_t j)
{
    char* item1 = p;
    char* item2 = p;

    item1 += i * elementSize;
    item2 += j * elementSize;

    while (elementSize-- > 0) {
        char temp = *item1;
        *item1 = *item2;
        *item2 = temp;
        item1++;
        item2++;
    }
}

編集:この StackOverflow answer to a similar questionも参照してください。

于 2013-05-15T05:11:31.303 に答える
-1

スワップ呼び出しでポインターを型キャストする必要があります。に変更しますswap ( ( void * )s, 0, 1 );

于 2013-05-15T03:47:07.173 に答える
-1

警告を回避するには、次のように関数を呼び出します。

swap((void *) s, 0, 1);

任意のポインターを void ポインターとしてキャストすることは常に安全です。

于 2013-05-15T03:48:06.423 に答える