Tôi đã có một vấn đề kỳ lạ mà tôi đã thu hẹp xuống test sau:Truy cập globals tĩnh trong một hàm nội tuyến
inl.h:
inline const char *fn() { return id; }
a.cc:
#include <stdio.h>
static const char *id = "This is A";
#include "inl.h"
void A()
{
printf("In A we get: %s\n", fn());
}
b.cc:
#include <stdio.h>
static const char *id = "This is B";
#include "inl.h"
void B()
{
printf("In B we get: %s\n", fn());
}
extern void A();
int main()
{
A();
B();
return 0;
}
Bây giờ khi tôi biên dịch này với g++ -O1 a.cc b.cc
nó có vẻ hoạt động chính xác. Tôi nhận được:
In A we get: This is A
In B we get: This is B
nhưng nếu tôi biên dịch với g++ -O0 a.cc b.cc
tôi nhận được:
In A we get: This is A
In B we get: This is A
Lưu ý rằng tôi thực sự cố gắng sử dụng ngữ nghĩa C11 ở đây, nhưng tôi sử dụng g ++ như gcc không hỗ trợ C11. Bây giờ theo như tôi thấy, nhìn vào cả thông số C11 và spec C++ (C++ 11 và các thông số cũ hơn - ngữ nghĩa của các hình cầu cục bộ và tĩnh dường như không thay đổi), nó nên làm những gì tôi muốn, và sự thất bại khi sử dụng -O0
là một lỗi trong gcc.
Điều này có đúng không, hoặc có điều gì đó ở đâu đó trong thông số kỹ thuật mà tôi thiếu mà có thể làm cho hành vi không xác định này không?
Sửa
Câu trả lời phổ biến dường như cho rằng fn
cần phải được khai báo là static
để làm việc này. Nhưng theo 6.7.4.6 của thông số C99 (6.7.4.7 trong thông số C11 - không chắc chắn về thông số C++):
Nếu tất cả các khai báo phạm vi tập tin cho một chức năng trong đơn vị dịch bao gồm inline function specifier không có extern, thì định nghĩa trong đơn vị dịch đó là định nghĩa nội tuyến . Định nghĩa nội tuyến không cung cấp định nghĩa bên ngoài cho hàm, và không cấm định nghĩa bên ngoài trong một đơn vị dịch khác.
Do không có rõ ràng extern
ở đây, nên là hai hàm nội tuyến độc lập không có tương tác với nhau. Không yêu cầu static
rõ ràng.
Sử dụng sửa lỗi tĩnh rõ ràng vấn đề cho C, nhưng không hoạt động cho hàm thành viên nội tuyến C++, vì từ khóa static
có nghĩa hoàn toàn khác trong trường hợp đó.
Không quan tâm, liệu hành vi có được nhân rộng nếu bạn thay thế bao gồm bằng định nghĩa hàm nội tuyến không? Nếu bộ tiền xử lý đang chạy như một thẻ đầu tiên độc lập như tôi tưởng tượng, bạn sẽ có thể đơn giản hóa trường hợp kiểm tra. –
Btw: phiên bản gcc nào? –
gcc 4.5.3 và 4.6.1 đều hoạt động theo cách này. –