Ví dụ tối thiểu có thể chạy được
Tính năng C ++ 17 tuyệt vời này cho phép chúng tôi:
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(¬main_i == notmain_func());
assert(notmain_i == 42);
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
inline constexpr int notmain_i = 42;
const int* notmain_func();
#endif
notmain.cpp
#include "notmain.hpp"
const int* notmain_func() {
return ¬main_i;
}
Biên dịch và chạy:
g++ -c -o notmain.o -std=c++17 -Wall -Wextra -pedantic notmain.cpp
g++ -c -o main.o -std=c++17 -Wall -Wextra -pedantic main.cpp
g++ -o main -std=c++17 -Wall -Wextra -pedantic main.o notmain.o
./main
GitHub ngược dòng .
Xem thêm: Biến nội tuyến hoạt động như thế nào?
Tiêu chuẩn C ++ về các biến nội tuyến
Tiêu chuẩn C ++ đảm bảo rằng các địa chỉ sẽ giống nhau. Bản nháp tiêu chuẩn C ++ 17 N4659
10.1.6 "Bộ chỉ định nội tuyến":
6 Một hàm hoặc biến nội tuyến có liên kết bên ngoài sẽ có cùng địa chỉ trong tất cả các đơn vị dịch.
cppreference https://en.cppreference.com/w/cpp/language/inline giải thích rằng nếu static
không được cung cấp, thì nó có liên kết bên ngoài.
Triển khai biến nội tuyến GCC
Chúng ta có thể quan sát cách nó được triển khai với:
nm main.o notmain.o
trong đó có:
main.o:
U _GLOBAL_OFFSET_TABLE_
U _Z12notmain_funcv
0000000000000028 r _ZZ4mainE19__PRETTY_FUNCTION__
U __assert_fail
0000000000000000 T main
0000000000000000 u notmain_i
notmain.o:
0000000000000000 T _Z12notmain_funcv
0000000000000000 u notmain_i
và man nm
nói về u
:
"u" Biểu tượng là một biểu tượng toàn cầu duy nhất. Đây là phần mở rộng GNU cho bộ tiêu chuẩn của các ràng buộc ký hiệu ELF. Đối với một ký hiệu như vậy, trình liên kết động sẽ đảm bảo rằng trong toàn bộ quá trình chỉ có một ký hiệu có tên và kiểu này được sử dụng.
vì vậy chúng tôi thấy rằng có một phần mở rộng ELF dành riêng cho việc này.
Pre-C ++ 17: extern const
Trước C ++ 17 và trong C, chúng ta có thể đạt được hiệu ứng rất giống với dấu extern const
, dẫn đến việc sử dụng một vị trí bộ nhớ duy nhất.
Nhược điểm inline
là:
- không thể tạo biến
constexpr
bằng kỹ thuật này, chỉ inline
cho phép rằng: Làm thế nào để khai báo constexpr extern?
- nó kém thanh lịch hơn vì bạn phải khai báo và xác định biến riêng biệt trong tiêu đề và tệp cpp
main.cpp
#include <cassert>
#include "notmain.hpp"
int main() {
// Both files see the same memory address.
assert(¬main_i == notmain_func());
assert(notmain_i == 42);
}
notmain.cpp
#include "notmain.hpp"
const int notmain_i = 42;
const int* notmain_func() {
return ¬main_i;
}
notmain.hpp
#ifndef NOTMAIN_HPP
#define NOTMAIN_HPP
extern const int notmain_i;
const int* notmain_func();
#endif
GitHub ngược dòng .
Các lựa chọn thay thế chỉ dành cho tiêu đề Pre-C ++ 17
Đây không phải là extern
giải pháp tốt, nhưng chúng hoạt động và chỉ chiếm một vị trí bộ nhớ duy nhất:
Một constexpr
hàm, bởi vì constexpr
hàm ýinline
và inline
cho phép (buộc) định nghĩa xuất hiện trên mọi đơn vị dịch :
constexpr int shared_inline_constexpr() { return 42; }
và tôi cá rằng bất kỳ trình biên dịch tốt nào cũng sẽ nội tuyến cuộc gọi.
Bạn cũng có thể sử dụng một const
hoặc constexpr
biến số nguyên tĩnh như trong:
#include <iostream>
struct MyClass {
static constexpr int i = 42;
};
int main() {
std::cout << MyClass::i << std::endl;
// undefined reference to `MyClass::i'
//std::cout << &MyClass::i << std::endl;
}
nhưng bạn không thể làm những việc như lấy địa chỉ của nó, hoặc nếu không nó sẽ được sử dụng bởi odr, hãy xem thêm: https://en.cppreference.com/w/cpp/language/static "Các thành viên tĩnh không đổi" và Định nghĩa dữ liệu tĩnh constexpr các thành viên
C
Trong C, tình huống cũng giống như C ++ trước C ++ 17, tôi đã tải lên một ví dụ tại: "static" có nghĩa là gì trong C?
Sự khác biệt duy nhất là trong C ++, const
ngụ ý static
cho toàn cầu, nhưng nó không có trong ngữ nghĩa C: C ++ của `static const` so với` const`
Bất kỳ cách nào để hoàn toàn nội tuyến nó?
TODO: có cách nào để nội dòng hoàn toàn biến mà không cần sử dụng bất kỳ bộ nhớ nào không?
Giống như những gì bộ tiền xử lý làm.
Điều này sẽ yêu cầu bằng cách nào đó:
- cấm hoặc phát hiện nếu địa chỉ của biến được sử dụng
- thêm thông tin đó vào các tệp đối tượng ELF và để LTO tối ưu hóa nó
Có liên quan:
Đã thử nghiệm trong Ubuntu 18.10, GCC 8.2.0.
const
.