エラー、バグ、質問 - ページ 2499

 
fxsaber:

その真相に迫りたいと思います。

データアライメントが

Print(sizeof(A)); // 2

これは、sizeof() の内部使用を考慮して行われているようです。つまり、sizeof() は物理メモリを考慮せず、単に各タイプをバイト単位で 合計しているのです。

アライメントは、ヘルプに書かれているように、物理メモリ内のデータの配置である "インポートされたDLL-関数に転送する" - 異なるコンパイラや言語でデータ型のサイズというか、それらがメモリに格納されている方法が異なる場合がありますので、構造体の各メンバーが"そのボックスを超えて上昇しなかった" - バイトを使用しなければならないのでパック(4)。

記事中のフブラはこんな感じです。

struct Foo
{
    char ch;
    int value;
};

1バイト:ch

2 バイト:空

3 バイト:空のTHIS はchar ch です。

4 バイト:空


5 バイト:値[0]。

6 byte: value[1]THIS はint 値 である

7 バイト:値[2]。

8 バイト:値[3]。


 
Igor Makanu:

これは、sizeof() の内部使用に対応するためで、つまりsizeof() は物理メモリを考慮せず、単に各タイプをバイト単位で 合計しているようです。

それはない。

struct A pack(4)
{
  short j;
  char i;
};

void OnStart()
{
  Print(sizeof(A)); // 4
}
 
fxsaber:

ということはありません。

の場合、sizeof()が構造体の「重さ」をバイト単位で正しくカウントしていることを確認した例です。

あとは物理メモリをチェックするだけですが、私見ではDLLを呼び出したときのみ動作し、開発者がメモリへのデータ保存を過剰に最適化していないことはないと思います;)- すなわち、もし pack(4) がコードの中で意図したとおりに使われないなら、 実行可能なコードでは無視されるかもしれません。

 
Igor Makanu:

そして、あなたの例では、sizeof()が構造体の「重さ」をバイト単位で正しくカウントしていることが確認されました。

だからこそ、「アライメントは実際にどのように機能するのか」という疑問が生まれます。ドキュメントとHabrは、その例でアルゴリズムを開示していない。

イゴール・マカヌ

物理メモリをチェックするために残っている唯一のものは、私の意見では、それは開発者がメモリ内のデータストレージを過剰に最適化しなかったという事実ではなく、DLLを呼び出すときにのみ動作します;)。- すなわち、もし pack(4) がコードの中で意図したとおりに使われないなら、 実行可能なコードでは無視されるかもしれません。

物理メモリも同様です。
struct A pack(4)
{
  short j;
  char i;
};

void OnStart()
{
  Print(sizeof(A)); // 4
  
  const int handle = FileOpen(__FILE__, FILE_WRITE | FILE_BIN);
  
  if (handle != INVALID_HANDLE)
  {
    A a = {0};
    
    FileWriteStruct(handle, a);
    Print(FileTell(handle)); // 4
    
    FileClose(handle);
  }
}
 
fxsaber:

ここで、アライメントが実際にどのように機能するのか、という疑問が生まれます。ドキュメントやhubrは、その例でアルゴリズムを開示していない。

MQL では、pack(4) を使用したときにデータがどのように保存されたかを確認するために、union を試すことができるかもしれません。

 
Igor Makanu:

特定のコンパイラに依存しますが、MQL の union でpack(4) を使用したときにデータがどのように保存されたかを確認することができます。

オフセットフなどの方法があります。


HH アライメントを設定することで、曖昧さをなくす役割があることがわかりました。ただし、自家用は除く。さて、そしてフィールドの順番がメモリ消費量に影響し、どうやらパフォーマンスにも影響することがはっきりわかりました。

 
fxsaber:

アライメントの設定は、曖昧さをなくすためのものであることがわかりました。ただし、自家用は除く。

開発者はしばしば、自分の開発品のパフォーマンスを相対的に向上させるためのトリックに走りますが、MQLにはコンパイラのディレクティブは存在しません - ソースコードの最適化を無効にするなど。- ネイティブコードのパフォーマンスやRAM使用量の違いを確認することはできません。


SZZ:ファイルへの書き込み の例が常に正しく動作するかどうかはわかりません。最近、ある人が、MQLはファイルへの書き込みにWin APIを使用していると書いていましたが、API関数との互換性のために何らかの仮定がなされているのかもしれません - ただし、これは私の推測であって、私はコンパイラ開発者ではありません ((

 
fxsaber:

他にも方法はあります。


アライメントを設定することで、アライメントを曖昧にしない役割を果たすことがわかった。ただし、自家用は除く。そして、フィールドの順番がメモリ消費量に影響することがお分かりいただけると思います。

アライメントが必要なのは、プロセッサが2つのキャッシュライン上にあるintを取得しないようにするためです。取り込み先は規制されておらず、コンパイラに依存するため、外部への転送はpack()に頼れず、手動での取り込みのみとなります。

 
Vict:

アライメントが必要なのではなく、プロセッサがキャッシュライン2本でintを取得しないようにすることが必要なのです。addする場所は規制されておらず、コンパイラに依存するため、外部に転送する際はpack()に頼れず、手動でaddするしかない。

腑に落ちました、皆さんありがとうございました。

 
fxsaber:

その真相に迫りたい。

ドキュメントに明確に書かれているのに、何を把握する必要があるのでしょうか。

構造体名を識別子(変数名や関数名)として使用することはできません。 MQL5では、構造体の要素はアライメントなしで、互いに直接追従することに注意してください。C++では、このような指示はコンパイラに対して

#pragma  pack(1)

などなど・・・。

つまり、MQL5ではアライメントが全くないのです。

Документация по MQL5: Основы языка / Типы данных / Структуры, классы и интерфейсы
Документация по MQL5: Основы языка / Типы данных / Структуры, классы и интерфейсы
  • www.mql5.com
Структура является набором элементов произвольного типа (кроме типа void). Таким образом, структура объединяет логически связанные данные разных типов. Объявление структуры Имя структуры нельзя использовать в качестве идентификатора (имени переменной или функции). Следует иметь ввиду, что в MQL5 элементы структуры следуют непосредственно друг...