Dường như biến toàn cục chưa được khởi tạo được coi là biểu tượng yếu trong Gcc. lý do đằng sau này là gì?Tại sao biến toàn cục chưa được khởi tạo là biểu tượng yếu?
Trả lời
gcc, trong chế độ C:
Uninitialised globals mà không được công bố extern
được coi là biểu tượng "chung", không những biểu tượng yếu.
Các ký hiệu chung được hợp nhất vào thời gian liên kết để tất cả chúng đều tham chiếu đến cùng một bộ nhớ; nếu có nhiều hơn một đối tượng cố gắng khởi tạo một biểu tượng như vậy, bạn sẽ nhận được một lỗi liên kết thời gian. (Nếu họ không rõ ràng khởi tạo bất cứ nơi nào, họ sẽ được đặt trong BSS, tức là khởi tạo vào 0.)
gcc, trong C++ chế độ:
Không giống nhau - nó không làm biểu tượng chung. Các hình cầu "Uninitialised" không được khai báo extern
được khởi tạo ngầm định với một giá trị mặc định (0 cho các kiểu đơn giản, hoặc hàm tạo mặc định).
Trong cả hai trường hợp, ký hiệu yếu cho phép biểu tượng khởi tạo bị ghi đè bởi biểu tượng khởi tạo không yếu cùng tên tại thời gian liên kết.
Để minh họa (tập trung vào các trường hợp C ở đây), tôi sẽ sử dụng 4 biến thể của một chương trình chính, đó là tất cả cùng trừ cách mà global
bị tuyên bố:
main_init.c:
#include <stdio.h> int global = 999; int main(void) { printf("%d\n", global); return 0; }
main_uninit.c, whic h bỏ qua việc khởi tạo:
#include <stdio.h> int global; int main(void) { printf("%d\n", global); return 0; }
main_uninit_extern.c, có thêm các
extern
keyword:#include <stdio.h> extern int global; int main(void) { printf("%d\n", global); return 0; }
main_weak_init.c, mà initialises
global
và tuyên bố đó là một biểu tượng yếu:#include <stdio.h> int global __attribute__((weak)) = 999; int main(void) { printf("%d\n", global); return 0; }
và another_def.c khởi tạo cùng một toàn cầu:
int global = 1234;
Sử dụng main_uninit.c
ngày của riêng mình mang đến cho 0:
$ gcc -o test main_uninit.c && ./test
0
nhưng khi another_def.c
được bao gồm như là tốt, global
được khởi tạo một cách rõ ràng và chúng tôi nhận được kết quả mong đợi:
$ gcc -o test main_uninit.c another_def.c && ./test
1234
(Lưu ý trường hợp này không thành công nếu bạn đang sử dụng C++.)
Nếu chúng ta thử với cả main_init.c
và another.def.c
thay vào đó, chúng tôi có 2 initialisations của global
, mà sẽ không làm việc:
$ gcc -o test main_init.c another_def.c && ./test
/tmp/cc5DQeaz.o:(.data+0x0): multiple definition of `global'
/tmp/ccgyz6rL.o:(.data+0x0): first defined here
collect2: ld returned 1 exit status
main_uninit_extern.c
ngày của riêng mình sẽ không làm việc ở tất cả - từ khóa extern
gây ra biểu tượng là một tài liệu tham khảo bên ngoài bình thường chứ không phải là một biểu tượng phổ biến, do đó mối liên kết phàn nàn:
$ gcc -o test main_uninit_extern.c && ./test
/tmp/ccqdYUIr.o: In function `main':
main_uninit_extern.c:(.text+0x12): undefined reference to `global'
collect2: ld returned 1 exit status
Nó hoạt động tốt khi khởi động từ another_def.c
i s bao gồm:
$ gcc -o test main_uninit_extern.c another_def.c && ./test
1234
Sử dụng main_init_weak.c
ngày của riêng mình cung cấp cho các giá trị chúng ta khởi tạo các biểu tượng yếu (999), như không có gì để ghi đè lên nó là:
$ gcc -o test main_init_weak.c && ./test
999
Nhưng kéo trong định nghĩa khác từ another_def.c
không hoạt động trong trường hợp này, bởi vì định nghĩa mạnh mẽ có ghi đè định nghĩa yếu trong main_init_weak.c
:
$ gcc -o test main_init_weak.c another_def.c && ./test
1234
Câu trả lời hay, thx. Tôi có thể hỏi nếu nó áp dụng cho C++? –
Giải thích tuyệt vời với các ví dụ. Bạn cũng có thể bao gồm tương tác yếu với các chức năng không? – Tomek
@Maciej - điểm tốt, quên điều này đã được gắn thẻ với cả hai khi viết câu trả lời của tôi ban đầu! Không, nó không giống với C++, vì vậy tôi đã cập nhật câu trả lời cho phù hợp. –
Đây có phải là ý của bạn không?
weak.c
#include <stdio.h>
int weak; /* global, weak, zero */
int main(void) {
printf("weak value is %d.\n", weak);
return 0;
}
strong.c
int weak = 42; /* global, strong, 42 */
mẫu chạy
$ gcc weak.c $ ./a.out weak value is 0. $ gcc weak.c strong.c $ ./a.out weak value is 42.
Các Đây là một phần mở rộng phổ biến, một phần mở rộng mà gcc sử dụng (nhờ Andrey).int weak;
trong weak.c là một tuyên bố, không phải là một định nghĩa. Hoặc bạn có thể nói đó là định nghĩa dự kiến. Định nghĩa thực là trong strong.c
khi tệp đối tượng đó được liên kết trong chương trình cuối cùng hoặc trong weak.c
nếu không.
Không đúng sự thật. 'int weak' trong' weak.c' là một định nghĩa.Một dự kiến, nhưng định nghĩa tuy nhiên. Chương trình ở trên * không * vi phạm các quy tắc của ngôn ngữ, nhưng được hỗ trợ dưới dạng tiện ích mở rộng không chuẩn. – AnT
Bất kỳ định nghĩa nào của một biểu tượng toàn cầu là hành vi không xác định, vì vậy gcc (hay đúng hơn là trình liên kết binutils GNU) là miễn phí để làm bất cứ điều gì nó muốn. Trong thực tế, nó tuân theo hành vi truyền thống để tránh vi phạm mã dựa vào hành vi này.
Bạn có ý nghĩa nhiều ** định nghĩa ** không? – pmg
Có, sửa chữa. –
Câu hỏi được dựa trên tiền đề không chính xác. Các biến toàn cục chưa được khởi tạo không phải là các biểu tượng yếu.
Dường như câu hỏi đề cập đến khả năng xác định cùng một đối tượng chưa được khởi tạo với liên kết bên ngoài trong nhiều đơn vị dịch. Chính thức, nó không được phép - nó là một lỗi trong cả C và C++.Tuy nhiên, ít nhất là trong C được công nhận theo tiêu chuẩn C99 là "mở rộng chung" của ngôn ngữ, thực hiện trong nhiều trình biên dịch thực tế cuộc sống
J.5 mở rộng Common
J.5.11 Nhiều ngoài định nghĩa
có thể có nhiều hơn một bên ngoài định nghĩa cho các định danh của một đối tượng , có hoặc không có rõ ràng sử dụng từ khóa bên ngoài; nếu các định nghĩa không đồng ý hoặc nhiều hơn được khởi tạo, hành vi là không xác định (6.9.2).
Lưu ý rằng, trái với niềm tin phổ biến, ngôn ngữ C nghiêm cấm giới thiệu nhiều định nghĩa của thực thể có liên kết bên ngoài trong chương trình, giống như C++.
6,9 định nghĩa bên ngoài
Một định nghĩa bên ngoài là một tuyên bố bên ngoài đó cũng là một nét của một hàm (trừ một định nghĩa inline) hoặc một đối tượng. Nếu một định tuyên bố với bên ngoài liên kết được sử dụng trong một biểu thức (trừ như một phần của toán hạng của một nhà điều hành sizeof mà kết quả là một hằng số số nguyên), ở đâu đó trong toàn bộ chương trình có phải chính xác một định nghĩa bên ngoài cho số nhận dạng ; nếu không, sẽ có không nhiều hơn.
Tuy nhiên, phần mở rộng cho phép điều này khá phổ biến với nhiều trình biên dịch C, trong đó GCC chỉ xảy ra là một.
Tính năng trình liên kết hỗ trợ là bắt buộc để triển khai các khối phổ biến FORTRAN. Bạn sẽ nhận thấy rằng GCC không bao gồm trình biên dịch FORTRAN trong bộ sưu tập. Vì các thư viện hỗ trợ được triển khai trong C, nên không có gì ngạc nhiên khi có một lượng nhỏ rò rỉ vô hại từ trình liên kết. – RBerteig
Bạn có thể đưa ra ví dụ về định nghĩa bên ngoài và khai báo bên ngoài không? – Thomson
Nó không chỉ FORTRAN, C++ nội tuyến chức năng và các mẫu instantiated ngầm cũng yếu. – MSalters
- 1. gcc, các biến toàn cục chưa được khởi tạo
- 2. Biến toàn cục chưa được khởi tạo ở đâu sau khi khởi tạo?
- 3. Tại sao biến ngoài của tôi chưa được khởi tạo?
- 4. Khởi tạo biến toàn cục và biến tĩnh thành 0 luôn luôn là không cần thiết?
- 5. theo dõi các biến tĩnh chưa được khởi tạo
- 6. Tại sao biên dịch lỗi "Sử dụng biến cục bộ chưa được gán"?
- 7. Tại sao các biến mẫu được khởi tạo trước khi hàm tạo được gọi là?
- 8. Biến Delphi có thể chưa được khởi tạo cảnh báo
- 9. Chuyển tuyên bố chưa được khởi tạo biến
- 10. Tại sao biến toàn cầu và tĩnh được khởi tạo thành giá trị mặc định?
- 11. AudioTrack: play() được gọi là AudioTrack chưa được khởi tạo
- 12. Lỗi C#: Sử dụng biến cục bộ chưa được gán
- 13. Tại sao phải có các biến cục bộ, bao gồm các biến nguyên thủy, luôn được khởi tạo trong Java?
- 14. Cách tạo biến toàn cục với Play Framework 2.0
- 15. Trường chỉ đọc được khởi tạo là null, tại sao?
- 16. Tại sao các thành viên lớp mẫu chưa được kích hoạt lại không được khởi tạo?
- 17. Tại sao các biến thành viên được khởi tạo trong các hàm tạo?
- 18. Cách tạo biến toàn cục trong Erlang
- 19. Các biến toàn cục được trình nạp elf khởi tạo như thế nào
- 20. Lỗi "yếu tố khởi tạo không phải là hằng số" khi cố gắng khởi tạo biến với const
- 21. Java: Tại sao tôi bắt buộc phải khởi tạo biến cục bộ nguyên thủy?
- 22. Tại sao các biến toàn cầu được coi là hành vi xấu?
- 23. Tại sao tạo các hàm Lua toàn cầu cục bộ?
- 24. Objective-C - biến toàn cục
- 25. "Yếu tố khởi tạo không phải là hằng số biên dịch" tại sao?
- 26. FactoryGirl, tại sao tôi đã đăng ký hoặc chưa được khởi tạo?
- 27. biến biến cục bộ javascript thành biến toàn cục
- 28. bộ khởi tạo đối tượng biến đổi?
- 29. Tạo biểu tượng khởi động động
- 30. tại sao khối catch đưa ra lỗi với biến không được khởi tạo trong Java
mẫu mã xin vui lòng – pmg
Làm thế nào để bạn đi đến kết luận đó, bạn đã thử gì, sự thật là gì? –
C hoặc C++? Có một sự khác biệt lớn. –