1

memcpy()メモリ割り当てに関しての結果がどうなったか知りたいです。

#include<stdio.h>
#include<string.h>

typedef struct {
  char myname[7] ; 
} transrules;

trans typedef struct {
  char ip ;
  int udp;
  transrules rules[256];
} __attribute__ ((__packed__)) myudp;

myudp __attribute__ ((__packed__)) udpdata ;

char arr[400] ;

int main() {            
  memset (&udpdata , 0 ,sizeof(udpdata));
  udpdata.ip = 'a' ;
  udpdata.udp = 13 ;
  udpdata.rules[0].myname = "lalla\0" ;
  memcpy (&arr , &udpdata, sizeof(udpdata));
  printf("%c",arr[0]);
  return 0;
}

コードに関しては、構造体の文字配列をどのように出力するのtransrulesでしょうか?

PS: はい、このコードはエラーをスローしますchar

定義された配列はタイプであるcharため、なぜ arr [1] は依然として整数値を受け入れるのmemcpy()ですか?

4

3 に答える 3

3

memcpyメモリを割り当てません。呼び出しでは、変数が定義されたときにmemcpy宛先のメモリarrが割り当てられました( )。arrchar arr[400]

十分なスペースを割り当てていないという問題があります。sizeof(updata)バイトをにコピーすると、おそらく 1+4+7*256=1797 になります (これは、プラットフォームで未使用のバイトを実際にすべて除外するかどうかarrによって異なります)。本当に必要な場合(おそらく必要ない場合)、少なくとも大きくしてください。で定義しても問題ありません。sizeof(int)__packed__arrsizeof(updata)char arr[sizeof(updata)]

構造体のレイアウトが何らかの外部フォーマットで定義されている場合は、代わりに固定サイズの型を使用する必要がありますint(プラットフォームに応じて 2 または 4 バイトであり、他のサイズになる可能性がありますが、それらに遭遇する可能性はほとんどありません)。

構造体のレイアウトが何らかの外部バイナリ形式で定義されていて、この形式で 1797 バイトを出力したい場合は、fwrite.

fwrite(updata, sizeof(updata), 1, stdout);

データの人間の表現が必要な場合はprintf、適切な形式仕様で使用してください。

printf("ip='%c' udp=%d\n", updata.ip, updata.ip);
for (i = 0; i < sizeof(updata.rules)/sizeof(updata.rules[0]); i++) {
    puts(updata.rules[i].myname);
}

名前にもかかわらず、char実際にはバイトの種類です。C には文字の個別の型はありません。文字定数 like'a'は、実際には整数値です (ほぼすべてのシステムでASCIIに従って 97 です)。で書いたり、バイトを文字として解釈しputcharたりするようなものです。printf("%c", …)

一方、ポインタ( などchar*) と整数を混同してもコンパイラがエラーを通知しない場合は、警告レベルを上げます。Gcc では、少なくともgcc -O -Wall.


コードを実際にコンパイルした後、主なエラーが表示されます (質問のコンパイラからのエラー メッセージをコピーして貼り付ける必要があります)。

udpdata.rules[0].myname = "lalla\0" ;

udpdata.rules[0].mynameバイト配列です。C では配列に代入できません。要素を 1 つずつコピーする必要があります。これは の配列でありchar、それに文字列をコピーしたいので、 を使用strcpyして文字列のすべてのバイトをコピーできます。一般に、一連のバイトの場合は、memcpy.

strcpy(udpdata.rules[0].myname, "lalla");

("lalla\0"は と同等であり"lalla"、C ではすべての文字列リテラルがゼロで終了することに注意してください。¹)strcpyはサイズの検証を実行しないため、割り当てたメモリに文字列 (最後の null 文字を含む) が収まるようにする必要があります。ターゲットのために。最大サイズを指定する場合は、strncatまたはなどの他の関数を使用できます。strlcpy

¹ゼロで終了しない1 つの例外 (およびこの例外のみ) があります。"lalla"たとえば、5 バイトの配列を初期化するときchar bytes[5] = "lalla"です。配列サイズが少なくとも 6 であるか指定されていない場合、終端のゼロ バイトがあります。

于 2012-09-05T00:07:09.290 に答える
1
// これは本当に悪いことです
udpdata.rules[0].myname = "lalla\0" ;

// 代わりにこれを行います。フィールドにリテラル文字列が必要です。
memcpy(udpdata.rules[0].myname, "lalla\0", 6);

....

// これは間違っています。arr はすでにポインターです。
memcpy (&arr , &udpdata, sizeof(udpdata));

// 代わりにこれを行う
mempcy (arr, &udpdata, sizeof(udpdate));

印刷に関しては、あなたのマシンの int の大きさはわかりませんが、4 バイトの場合は

printf("%.7s", &arr[1+4]);

コンテンツを印刷したいのに、なぜすべてを char 配列に変換したいのかわかりません。構造体とforループを使用するだけです。とにかく、C配列について読みたいと思うかもしれません。

于 2012-09-04T23:56:07.290 に答える
1

コードに関して、transrules 構造体の文字配列をどのように出力するのでしょうか?

/* incorrect -> udpdata.rules[0].myname = "lalla\0" ; */
strcpy(udpdata.rules[0].myname,"lalla") ;
printf("%s\n",udpdata.rules[0].myname);

定義された配列は char 型であるため、 arr [1] が memcpy で整数値を受け入れるのはなぜですか?

memcpy は、コピー先の基になるデータ型が何であるかを知りません。void ポインターを取り、1 つ以上のバイトの値を 1 つ以上の他のバイトにコピーします。

void * memcpy ( void * destination, const void * source, size_t num );
于 2012-09-05T00:08:02.283 に答える