Linux 86版5.7節Cスタイルデータ構造メモリレイアウトの構造体配列


配列と構造体の2つの非原生的なデータ型を探究した後,この2つのタイプが構造体配列に結合し,どのような特徴があるかを知りたいかもしれない.
まず例を見てみましょう.
  #include <stdlib.h>
  struct xuzhina_dump_c05_s3_3
  {
      short idx;
      int sq;
  };
  
  void init( struct xuzhina_dump_c05_s3_3* test, int n )
 {
     for ( int i = 0; i < n; i++ )
     {
         test[i].idx = i;
         test[i].sq = i*i;
     }
 }
 
 int sum( struct xuzhina_dump_c05_s3_3* test, int n )
 {
     int sum = 0;
     for ( int i = 0; i < n; i++ )
     {
         sum += test[i].sq;
     }
     return sum;
 }
 
 int main(int argc, char* argv[] )
 {
     if ( argc < 2 )
     {
         return 1;
     }

     int num = atoi( argv[1] );

     struct xuzhina_dump_c05_s3_3* test =
         (struct xuzhina_dump_c05_s3_3*)malloc( num * sizeof( struct xuzhina_dump_c05_s3_3 ) );
 
     init( test, num );
 
     return sum( test, num );
 }

アセンブリ(initとsumのみ)
(gdb) disassemble init
Dump of assembler code for function _Z4initP21xuzhina_dump_c05_s3_3i:
   0x080484d0 <+0>:     push   %ebp
   0x080484d1 <+1>:     mov    %esp,%ebp
   0x080484d3 <+3>:     sub    $0x10,%esp
   0x080484d6 <+6>:     movl   $0x0,-0x4(%ebp)		;i
   0x080484dd <+13>:    jmp    0x8048511 <_Z4initP21xuzhina_dump_c05_s3_3i+65>

   0x080484df <+15>:    mov    -0x4(%ebp),%eax
   0x080484e2 <+18>:    lea    0x0(,%eax,8),%edx		;edx = i*8
   0x080484e9 <+25>:    mov    0x8(%ebp),%eax		;eax = test
   0x080484ec <+28>:    add    %eax,%edx				;edx = test[i]
   0x080484ee <+30>:    mov    -0x4(%ebp),%eax		;i
   0x080484f1 <+33>:    mov    %ax,(%edx)			;test[i].idx = i
   0x080484f4 <+36>:    mov    -0x4(%ebp),%eax		;i
   0x080484f7 <+39>:    lea    0x0(,%eax,8),%edx		;edx = i*8
   0x080484fe <+46>:    mov    0x8(%ebp),%eax		;eax = test
   0x08048501 <+49>:    add    %eax,%edx				;edx = test[i]
   0x08048503 <+51>:    mov    -0x4(%ebp),%eax		;eax = i
   0x08048506 <+54>:    imul   -0x4(%ebp),%eax		;eax *= i
   0x0804850a <+58>:    mov    %eax,0x4(%edx)		;test[i].sq = eax
   0x0804850d <+61>:    addl   $0x1,-0x4(%ebp)			;i++
   0x08048511 <+65>:    mov    -0x4(%ebp),%eax
   0x08048514 <+68>:    cmp    0xc(%ebp),%eax
   0x08048517 <+71>:    setl   %al
   0x0804851a <+74>:    test   %al,%al
   0x0804851c <+76>:    jne    0x80484df <_Z4initP21xuzhina_dump_c05_s3_3i+15>

   0x0804851e <+78>:    leave  
   0x0804851f <+79>:    ret    
End of assembler dump.

(gdb) disassemble sum
Dump of assembler code for function _Z3sumP21xuzhina_dump_c05_s3_3i:
   0x08048520 <+0>:     push   %ebp
   0x08048521 <+1>:     mov    %esp,%ebp
   0x08048523 <+3>:     sub    $0x10,%esp
   0x08048526 <+6>:     movl   $0x0,-0x4(%ebp)		;sum
   0x0804852d <+13>:    movl   $0x0,-0x8(%ebp)		;i
   0x08048534 <+20>:    jmp    0x804854f <_Z3sumP21xuzhina_dump_c05_s3_3i+47>

   0x08048536 <+22>:    mov    -0x8(%ebp),%eax		;i
   0x08048539 <+25>:    lea    0x0(,%eax,8),%edx
   0x08048540 <+32>:    mov    0x8(%ebp),%eax		;test
   0x08048543 <+35>:    add    %edx,%eax
   0x08048545 <+37>:    mov    0x4(%eax),%eax		;test[i].sq
   0x08048548 <+40>:    add    %eax,-0x4(%ebp)
   0x0804854b <+43>:    addl   $0x1,-0x8(%ebp)			;i++
   0x0804854f <+47>:    mov    -0x8(%ebp),%eax
   0x08048552 <+50>:    cmp    0xc(%ebp),%eax		;i < n 
   0x08048555 <+53>:    setl   %al
   0x08048558 <+56>:    test   %al,%al
   0x0804855a <+58>:    jne    0x8048536 <_Z3sumP21xuzhina_dump_c05_s3_3i+22>

   0x0804855c <+60>:    mov    -0x4(%ebp),%eax
   0x0804855f <+63>:    leave  
   0x08048560 <+64>:    ret    
End of assembler dump.

上のアセンブリから、構造体配列の特徴は次のとおりです.
1.まず配列の先頭アドレスを見つける
2.インデックスに基づいて各要素を見つけ、各要素のアドレスを取得します.
3.さらに各要素のアドレスを構造体ベースアドレスとし、メンバー変数のアドレスを取得する.