2012-09-30 31 views
9

は私がインクリメント構造体のメンバ

struct my_struct 
{ 
    int num; 
}; 

を次のように定義された構造体を持っていると言う....ここ

私はmy_structへのポインタを持っていると私はnum

void foo(struct my_struct* my_ptr) 
{ 
    // increment num 
    // method #1 
    my_ptr->num++; 

    // method #2 
    ++(my_ptr->num); 

    // method #3 
    my_ptr->++num; 

} 
に増加をしたいです

numを3つ増やす方法は同じですか? これまでのところ、プリインクリメントはポストインクリメントより効率的でしたか?

ありがとうございます!

答えて

8

最初の2つは、同じような効果があります(そのような行の場合)。しかし、3番目の方法は有効なCコードではありません(++を置くことはできません)。

効率的には違いはありません。 C++では、イテレータのようなポインタ以外のデータ型をインクリメントするときに、人々が話を聞いたことがあるかもしれません。場合によっては、プリインクリメントが速くなる場合もあります。

GCC Explorerを使用すると、生成されたコードが表示されます。

void foo(struct my_struct* my_ptr) 
{ 
    my_ptr->num++; 
} 

void bar(struct my_struct* my_ptr) 
{ 
    ++(my_ptr->num); 
} 

出力:あなたが見ることができるように

foo(my_struct*):      # @foo(my_struct*) 
    incl (%rdi) 
    ret 

bar(my_struct*):      # @bar(my_struct*) 
    incl (%rdi) 
    ret 

、全く違いはありません。

あなたが式の中でそれらを使用する際に最初の二つの間の唯一の可能な違いは次のとおりです。

my_ptr->num = 0; 
int x = my_ptr->num++; // x = 0 

my_ptr->num = 0; 
int y = ++my_ptr->num; // y = 1 
2

あなたの唯一の意図はNUMの値をインクリメントすることであれば、第一及び第二の方法は、に同じintented結果が得られます呼び出し先メソッド。

次のようにコードを変更する場合は、あなたは、GCC(アセンブリレベルのコード)によって生成されたコードの違いを見ることができます:

struct my_struct 
{ 
    int num; 
}; 

void foo(struct my_struct* my_ptr) 
{ 
     printf("\nPost Increment: %d", my_ptr->num++); 
} 

int main() 
{ 
     struct my_struct a; 
     a.num = 10; 

     foo(&a); 
} 

今使ってコンパイル:gccの-masm =インテル - S structTest.c -o structTest.s gccがアセンブリコードを生成するように求めます。

structTest.sをテキストエディタで開きます。

foo: 
.LFB0: 
     push rbp 
     mov  rbp, rsp 
     sub  rsp, 16 
     **mov  QWORD PTR [rbp-8], rdi** 
     mov  rax, QWORD PTR [rbp-8] 
     mov  eax, DWORD PTR [rax] 
     mov  edx, eax 
     **lea  ecx, [rax+1]** 
     mov  rax, QWORD PTR [rbp-8] 
     mov  DWORD PTR [rax], ecx 
     mov  eax, OFFSET FLAT:.LC0 
     mov  esi, edx 
     mov  rdi, rax 
     mov  eax, 0 
     call printf 
     leave 
     ret 
     .cfi_endproc 

main: 
.LFB1: 
     push rbp 
     mov  rbp, rsp 
     sub  rsp, 16 
     **mov  DWORD PTR [rbp-16], 10 
     lea  rax, [rbp-16] 
     mov  rdi, rax 
     call foo** 
     leave 
     ret 
     .cfi_endproc 

そして、あなたはインクリメントを事前に操作を変更したときに、follwoingコードが生成されます。

foo: 
.LFB0: 
     .cfi_startproc 
     push rbp 
     mov  rbp, rsp 
     sub  rsp, 16 
     **mov  QWORD PTR [rbp-8], rdi** 
     mov  rax, QWORD PTR [rbp-8] 
     mov  eax, DWORD PTR [rax] 
     **lea  edx, [rax+1]** 
     mov  rax, QWORD PTR [rbp-8] 
     **mov  DWORD PTR [rax], edx** 
     mov  rax, QWORD PTR [rbp-8] 
     **mov  edx, DWORD PTR [rax]** 
     mov  eax, OFFSET FLAT:.LC0 
     mov  esi, edx 
     mov  rdi, rax 
     mov  eax, 0 
     call printf 
     leave 
     ret 
     .cfi_endproc 

だから、あなたは、第二の場合には、コンパイラがNUM値とパスをインクリメントしていることがわかりますこのnum値でprintf()を呼び出します。

性能面では、メモリ位置に触れる回数が少ないため、ポストインクリメントが効率的になると思います。

重要な行は、上記のコードで**の間にマークされています。