2012-02-22 17 views
7

Xét đoạn mã sau:Tại sao GCC phân bổ không gian ngăn xếp riêng biệt cho các công đoàn địa phương trong các phạm vi khác nhau?

#include <stdlib.h> 

#ifndef TRY 
#define TRY struct 
#endif 

TRY testme 
{ 
    int one; 
    int two; 
    char three; 
    int four; 
}; 

int 
main (void) 
{ 
    { 
    volatile TRY testme one; 

    one.one = 2; 
    one.three = 7; 
    } 

    { 
    volatile TRY testme twos; 

    twos.one = 3; 
    } 

    { 
    volatile TRY testme one; 

    one.one = 4; 
    } 

    { 
    volatile TRY testme twos; 

    twos.one = 5; 
    } 

    { 
    volatile TRY testme twos; 

    twos.one = 6; 
    } 

    { 
    volatile TRY testme twos; 

    twos.one = 6; 
    } 

    return EXIT_SUCCESS; 
} 

Biên soạn như là cho x86 được (có nghĩa là testme là một struct), ngăn xếp kích thước trình biên dịch phân bổ cho chính là 16 byte.

$ gcc -g -O2 test.c -o test 
$ objdump -d ./test | ./checkstack.pl i386 | grep main 
16 main 

Tuy nhiên, biên soạn với TRY định nghĩa công đoàn (có nghĩa là testme là một liên minh), ngăn xếp kích thước trình biên dịch phân bổ cho chính là 32 byte:

$ gcc -DTRY=union -g -O2 test.c -o test 
$ objdump -d ./test | ./checkstack.pl i386 | grep main 

Hơn nữa, bất kỳ phiên bản bổ sung của struct/union được định nghĩa trong phạm vi bổ sung, sẽ tạo ra phân bổ stack lớn hơn khi sử dụng một union, nhưng sẽ không mở rộng phân bổ stack khi được sử dụng như một struct.

Bây giờ, điều này không có ý nghĩa - công đoàn nên mất ít không gian ngăn xếp, nếu có, không nhiều hơn, sau đó một cấu trúc với các lĩnh vực tương tự!

Dường như GCC đối xử với các công đoàn như được sử dụng đồng thời ngay cả khi ở các phạm vi khác nhau, nhưng không làm tương tự cho các cấu trúc.

Một số chi tiết làm rõ:

  1. dễ bay hơi được sử dụng để ngăn chặn các trình biên dịch từ tối ưu hóa đi những bài tập. Mất biến động và biên dịch không có tối ưu hóa sẽ tạo ra kết quả tương tự.

  2. Ngay cả khi testme là một cấu trúc có liên minh là một trong các thành viên, thì hành vi tương tự cũng được quan sát. Nói cách khác - nó là đủ mà một trong những thành viên của một cấu trúc là một liên minh cho GCC để phân bổ stack riêng biệt.

  3. Trình biên dịch là phiên bản gcc 4.4.3 (Ubuntu 4.4.3-4ubuntu5) nhưng các phiên bản GCC khác cho các kiến ​​trúc khác cũng cho thấy hành vi tương tự.

  4. checkstack.pl chỉ cần tìm kiếm đầu ra objdump cho các hướng dẫn được sử dụng để cấp phát ngăn xếp (phụ cho con trỏ ngăn xếp).

Câu hỏi của tôi:

  1. Tại sao GCC làm điều này? đây có phải là lỗi hay có lý do cho hành vi này không?
  2. Giả sử đây không phải là lỗi, có cách nào đó để giải quyết vấn đề này và buộc GCC phân bổ ngăn xếp cho các mảng giống như công đoàn.

Làm rõ: Câu hỏi của tôi không phải là lý do tại sao cấu trúc hoặc công đoàn có kích thước lớn hơn so với kích thước của nó. Tôi hiểu lý do là đệm cho căn chỉnh. Vấn đề của tôi là trình biên dịch phân bổ nhiều khung stack cho các trường hợp khác nhau của union mặc dù chúng được định nghĩa trong các phạm vi khác nhau trong khi nó không nên và thực sự không làm tương tự cho một struct với cùng các trường.

Cảm ơn!

+0

lẽ công đoàn không cũng được tối ưu hóa tại '-O2' (chưa)? Có một cái nhìn tại mã assembler được tạo ra. Ngoài ra, hãy thử tắt 'strict-aliasing'. Oh, và thử GCC hiện tại. –

+1

Bạn đã xem xét [câu hỏi này] (http://stackoverflow.com/questions/8453881/sizeof-union-larger-than-expected-how-does-type-alignment-take-place-here) và [ cái này] (http://stackoverflow.com/questions/7212585/why-is-my-unions-size-bigger-than-i-expected)? Nó có vẻ là một vấn đề về ràng buộc padding và liên kết – Coren

+0

@ Anony-Mousse -fno-strict-aliasing tạo ra kết quả tương tự. Tôi đang xây dựng GCC mới nhất để kiểm tra. – gby

Trả lời

8

Dường như ít nhất một nỗ lực đã được thực hiện để thư giãn chứng hoang tưởng răng cưa nghiêm ngặt của gcc liên quan đến công đoàn.

Bạn có thể muốn đảm bảo rằng nguồn gcc bạn biên dịch từ đã này hoặc tương đương vá áp dụng: http://codereview.appspot.com/4444051/

+0

Đó chính xác là những gì tôi đang tìm kiếm. Cảm ơn bạn rất nhiều :-) – gby

0

Dường như lớp đệm và định nghĩa kích thước mặc định cơ bản của Int.

Trong 32 cắn bản đồ bộ nhớ sẽ là: One (2 byte) Hai (2 byte) Ba (1 byte) (1 byte) đệm bốn (2 byte)

Tổng số - 8 byte.

trong 64 cắn nó sẽ là: One (4 byte) Hai (4 byte) Ba (1 byte) (3 byte đệm) Bốn (4 byte)

Tổng - 16 byte.

Nếu bạn thay đổi "int" thành "short int", bộ nhớ sẽ trông khác.

+1

Nhưng với tư cách là một "công đoàn", toàn bộ điều chỉ nên lấy 4 byte, bất kể là 32 hay 64 bit. –

+0

Tôi không có vấn đề với một cấu trúc đơn lẻ hoặc công đoàn mất bao nhiêu. Vấn đề của tôi là GCC dường như phân bổ không gian stack khác nhau cho các trường hợp khác nhau của union được định nghĩa trong các phạm vi khác nhau, mặc dù nó không cần phải làm điều đó và thực sự không làm điều đó cho struct – gby

+0

Ngay cả khi một công đoàn phụ thuộc vào những gì xảy ra tiếp theo. nếu nó nằm trong mảng của công đoàn - nó sẽ lấy 32 bit ngay cả dưới 64 bit.nếu nó biến, sau đó trên hệ thống 64 bit, nó sẽ được đệm đến 64 bit. Nó không phải là phạm vi, nó là "những gì đến tiếp theo". –

Các vấn đề liên quan