8

コード:

union foo
{
    char c;
    int i;
};

void func(void * src)
{
    union foo dest;
    memcpy(&dest, src, sizeof(union foo));   //here
}

私がfunc()このように呼び出すと:

int main()
{
    char c;
    int i;
    func(&c);
    func(&i);
    return 0;
}

の呼び出しfunc(&c)で、 のサイズcが より小さいのはsizeof(union foo)危険ですよね?

の行はmemcpy正しいですか?そうでない場合、それを修正する方法は?

私が欲しいのは、へのポインターをmemcpyコピーするための安全な呼び出しです。void *union


ちょっとした背景: これは非常に複雑な関数から抽出されたものであり、パラメーターをfunc()含めることの署名は私の手に負えません。void *もちろん、この例は何の役にも立ちません。これは、最小限のコードで例を提供するために関係のないコードをすべて削除したためです。

4

5 に答える 5

6

の呼び出しfunc(&c)で、 のサイズcが より小さいのはsizeof(union foo)危険ですよね?

そうです、これは未定義の動作につながります。destには、周囲のメモリ領域からのバイトが含まれる可能性が高く、cこれらはコンパイラの内部動作に依存します。もちろん、 にアクセスするだけdest.cであれば、ほとんどの場合問題は発生しません。

しかし、もっと具体的にさせてください。C 標準によると、書き込みとdest.c読み取りdest.i常に未定義の動作を引き起こします。ただし、ほとんどのプラットフォームのほとんどのコンパイラには、これらのケースに対しても明確に定義された動作があります。多くの場合、標準が何を言っているかにかかわらず、書くこととdest.c読むdest.iことは理にかなっています。ただし、この場合、からの読み取りはdest.i未知の周囲の変数の影響を受けるため、標準の観点からだけでなく、非常に実用的な意味でも未定義です。

考慮すべきまれなシナリオもありcます。割り当てられたメモリ ページの最後にある可能性があります。(これはオペレーティング システムから割り当てられたメモリ ページを指し、最終的にはメモリ管理ユニット (MMU) ハードウェアから割り当てられたメモリ ページを指し、malloc友人によって行われたブロック単位のユーザー空間割り当てではありません。) この場合、その 1 バイトを超える読み取りはアクセスを引き起こす可能性があります。マップされていないメモリに移動するため、重大なエラーが発生します。ほとんどの場合、プログラムがクラッシュします。main の自動変数としての your の場所を考えるとc、これはありそうにないように思えますが、このコード スニペットは単なる例であると考えています。

の行はmemcpy正しいですか?そうでない場合、それを修正する方法は?

何をしたいかによります。現状では、コードはあまり意味をなさないので、どのような適切で合理的なアプリケーションを念頭に置いているのかわかりません。おそらくsizeofsrcオブジェクトを に渡す必要がありますfunc

于 2013-09-02T08:02:02.623 に答える
3

memcpy の行は正しいですか? そうでない場合、それを修正する方法は?

voidポインタが指すメモリのサイズを渡す必要があるので、これだけのサイズがあることがわかるsrcので、この量のデータをコピーするだけで済みます...

さらに安全のため に、宛先のサイズを計算し、それに基づいてサイズを渡す必要があるため 、読み取りと書き込みの両方での不正なアクセスを回避できます。

于 2013-09-02T08:05:55.687 に答える
0

コピーするサイズとサイズがわかっているので、より明示的な関数を指定しないのはなぜですか。関数に、void ポインターが指す正しいサイズのメモリをコピーする方法を知らせてください。

union foo
{
    char c;
    int i;
};

void func(void * src, const char * type)
{
    union foo dest;

    if(strcmp(type, "char") == 0){
      memcpy(&dest, src, 1);
    }else if(...){

    }
}
于 2013-09-02T08:33:59.880 に答える