15

アプリケーションを C の ARM プラットフォームに移植しています。アプリケーションは x86 プロセッサでも実行され、下位互換性が必要です。

現在、変数の配置に問題があります。__attribute__((aligned(4),packed))構造体の開始が 4 バイトの境界に位置合わせされ、パックされたステートメントのために内部が変更されていないため、gcc のマニュアルを読みました 。

もともと私はこれを持っていましたが、4 バイト境界に合わせずに配置されることがあります。

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((packed)) CHALLENGE;

なのでこれに変更。

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((aligned(4),packed)) CHALLENGE;

構造体が 4 バイト境界に整列され、内部データが 4 バイト境界に整列されているため、前に述べた理解は正しくないようですが、エンディアンのために構造体のサイズが増加しました。サイズは 42 から 44 バイトです。42 バイトの構造体に依存する他のアプリケーションがあるため、このサイズは重要です。

必要な操作を実行する方法を説明してもらえますか。どんな助けでも大歓迎です。

4

6 に答える 6

16

あなたsizeof(yourstruct)が42バイトであることに依存しているなら、あなたは移植性のない仮定の世界に噛まれようとしています。これが何のためにあるのかは言っていませんが、構造体の内容のエンディアンも重要である可能性が高いため、x86との不一致もある可能性があります。

unsigned char[42]このような状況では、確実に対処する唯一の方法は、重要な部分で使用することだと思います。この42バイトのブロックのどこにどのフィールドがあり、どのエンディアンであるかを正確に指定することから始め、次にその定義を使用して、それと相互作用できる構造体との間で変換するコードを記述します。コードは、オールアットワンスシリアル化コード(別名マーシャリング)、またはゲッターとセッターの束のいずれかである可能性があります。

于 2010-03-31T16:02:55.720 に答える
6

これは、メンバー単位ではなく構造体全体の読み取りが失敗する理由の 1 つであり、回避する必要があります。

この場合、パッキングと 4 での位置合わせは、2 バイトのパディングがあることを意味します。これは、すべての項目が 4 でアラインされたまま、型を配列に格納するためのサイズに互換性がなければならないために発生します。

次のようなものがあると思います:

read(fd, &obj, sizeof obj)

異なるデータに属する 2 つのパディング バイトを読みたくないため、サイズを明示的に指定する必要があります。

read(fd, &obj, 42)

維持できるもの:

typedef struct {
  //...
  enum { read_size = 42 };
} __attribute__((aligned(4),packed)) CHALLENGE;

// ...

read(fd, &obj, obj.read_size)

または、C で C++ の一部の機能を使用できない場合:

typedef struct {
  //...
} __attribute__((aligned(4),packed)) CHALLENGE;
enum { CHALLENGE_read_size = 42 };

// ...

read(fd, &obj, CHALLENGE_read_size)

次のリファクタリングの機会に、関数内に簡単にカプセル化できる各メンバーを個別に読み始めることを強くお勧めします。

于 2010-03-31T16:04:40.033 に答える
4

Linux、Windows、Mac、C、Swift、Assembly などから構造を行ったり来たりしてきました。

問題は、それができないということではなく、怠けてはいられず、自分のツールを理解しなければならないということです。

使用できない理由がわかりません:

typedef struct  
{  
 unsigned int code;  
 unsigned int length;  
 unsigned int seq;  
 unsigned int request;  
 unsigned char nonce[16];  
 unsigned short  crc;  
} __attribute__((packed)) CHALLENGE;

それを使用することができ、特別なコードや巧妙なコードは必要ありません。ARM と通信するコードをたくさん書いています。構造は物事を機能させるものです。__attribute__ ((packed))私の友達です。

両方で何が起こっているかを理解していれば、「傷ついた世界」にいる可能性はゼロです.

最後に、どうやって 42 や 44 を取得するのか、一生わかりません。Int は 4 バイトか 8 バイトです (コンパイラによって異なります)。これにより、数値は 16+16+2=34 または 32+16+2=50 のいずれかになります (実際にパックされていると仮定します)。

私が言うように、ツールを知ることは問題の一部です。

于 2018-08-30T20:51:10.237 に答える
3

あなたの本当の目標は何ですか?

ファイル内またはネットワーク上で特定の形式のデータを処理する場合は、コンパイラ構造体間でデータを移動するマーシャリング/シリアル化ルーチンを作成します。これは、内部のデータを処理する方法を表しますプログラムと、データがワイヤ/ファイル上でどのように見えるかを扱う char 配列。

次に、慎重に処理する必要があり、プラットフォーム固有のコードが含まれる可能性があるのは、マーシャリング ルーチンだけです。また、現在および将来、どのプラットフォームに移植する必要があるとしても、マーシャリングされたデータが構造体との間で適切にやり取りされることを確認するために、適切で厄介な単体テストを作成することができます。

于 2010-03-31T19:45:23.260 に答える
0

問題は、42 が 4 で割り切れないことであり、これらの構造体のいくつかを背中合わせに配置すると、それらが整列しなくなることだと思います (たとえば、いくつかの構造体にメモリを割り当て、 でサイズを決定しますsizeof)。これらの場合、サイズを 44 にすると、要求どおりに配置が強制されます。ただし、各構造体メンバーの内部オフセットが同じままである場合は、44 バイトの構造体を 42 バイトであるかのように扱うことができます (後続のデータを正しい境界に揃えるように注意する限り)。

試してみるべき 1 つのトリックは、これらの両方の構造体を 1 つのユニオン タイプ内に配置し、そのような各ユニオン内から 42 バイト バージョンのみを使用することです。

于 2010-03-31T15:55:50.403 に答える
-3

私は Linux を使用しているので、 それによってecho 3 > /proc/cpu/alignment警告が表示され、配置の問題が修正されることがわかりました。これは回避策ですが、構造がずれていない場所を特定するのに非常に役立ちます。

于 2010-04-01T14:47:15.467 に答える