2011-01-11 11 views
1

私は最近、Delphiプロジェクトの作業を開始し、非常に奇妙なコードを発見しました。デルファイでレコードのポインタをcharの配列に割り当てる - もう一度やりますか?

// Type declarations 

type 
    TDataSet = record 
    VolumeLevel : char; 
    DeviceMasks : char; 
    DeviceList: array [1..MAX] of array [1..8] of char; 
    DisplayList: array [1..MAX] of array [1..8] of char; 
end; 

type 
    TSerialPacket = record 
    Preamble: array[1..4] of byte; 
    PacketType: byte; 
    PacketLen: byte; 
    Data: array of char; 
    Checksum: byte; 
end; 

... 

// Private fields 

Packet : TSerialPacket; 
DataSet : TDataSet; 

... 

// Actual procedure 

SetLength(Packet.Data, sizeof(DataSet)); 
Packet.Data := @DataSet; 

私はDelphiを使用していないので、このコードは私には分かりません。コンパイラはこれが問題ないと思い、コードを実行することができます。私はデバッガでそれを走らせましたが、Packet.Dataの値は変わっていないようです。誰がこれが何をしているか教えてもらえますかchar型の配列にカスタムレコードのポインタを代入するのは非常に奇妙なようです。

また、何らかの理由でSetLengthがエラーを発生させます。 "プロジェクトFoo.exeが例外クラスEAccessViolationを 'モジュール' Foo.exe 'のアドレス00403860のアクセス違反で発生させました。アドレス00000000の読み取り"。 WorkingとCrashingの両方の実行中にPacket.Dataの値は()であり、dataofのsizeofは260です。正確に何が変更されているのかを特定することはできませんでした。私が知る限り、SetLengthはPacket.DataやDataSet以外の変数に依存してはいけません。

(Iは、Windows 7上のDelphi XEを使用)

+0

FWIW:D2007で、私はコードを簡単に見てみると、 '[DCC Fehler] Project1.dpr(35):E2010 Inkompatible Typen: 'dynamic array'と' Pointer''を得ました。 –

+0

奇妙な。 Packet.Data:= DataSetで「互換性のない型: 'dynamic array'とTDataSet」というエラーが発生しました。しかし、Packet.Data:= @DataSetはOKです。 –

+0

Ah - mea culpa。私は{$ TYPEDADDRESS ON}を含むように私のデフォルトのコンパイラオプションを変更しました - これは違いを説明します。しかし、あなたが現在経験しているように、おそらくそれも含めるべきです。 :-) –

答えて

1

する必要があります推測する私は私が間違って何が起こっているか知っていると思いますあなたのコードで...

すでに述べたように、これはかなり悪いです:

SetLength(Packet.Data, sizeof(DataSet)); 
Packet.Data := @DataSet; 

私は、コードがSetLengthでクラッシュするのは、2回目の実行時のみです。 何が起こることはここで

Packet.Data := @DataSet; 

で、シャアポインタの配列は、データセットの変数のアドレスに置き換えられます。 "Setlength"によって作成されたCharの配列は、次に解放されます。

2回目にSetLengthを取得すると、Charの配列へのポインタと考えるコンパイラは、実際にはTDataSetへのポインタです。それは私がそれはあなたが経験している任意の付加的な問題を見つけることに役立ちます願ってい

(コンパイラが1ということができないであろうことを除いて)

SetLength(@Dataset, SizeOf(Dataset)); 

を呼び出すことに似ています。

+0

これは問題を解決したので、私はUlrichの答えの代わりにこれを受け入れています。 –

4

私は最後の行(

Packet.Data := @DataSet; 

は)むしろ

Move(DataSet, Packet.Data[0], SizeOf(DataSet)); 
+0

これらの2つの違いは何ですか?上の方が何らかの非推奨の方法ですか、それともいつも醜いハックですか? –

+0

AFAICSポインタの割り当てはバグです。私はあなたのテストサンプルよりもわずかに複雑なコードで確実に動作するとは信じていません。私が上でコメントしたように、誰かに$ TYPEDADDRESSをONに設定するよう勧めます。コンパイラはこの種のバグを検出します。 –

+0

これは私の全面的な問題を解決していませんでしたが、私はそれを受け入れているとマークしています。上記の限定されたコードサンプルを見ても問題が解決できるかどうかはわかりません。私はそれを解決するときにこの質問に戻るでしょう。 –

関連する問題