Contoh minimal runnable
Fitur C ++ 17 yang luar biasa ini memungkinkan kita untuk:
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;
}
Kompilasi dan jalankan:
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 upstream .
Lihat juga: Bagaimana cara kerja variabel sebaris?
Standar C ++ pada variabel sebaris
Standar C ++ menjamin bahwa alamatnya akan sama. C ++ 17 N4659 standard draft
10.1.6 "The inline specifier":
6 Fungsi atau variabel sebaris dengan hubungan eksternal harus memiliki alamat yang sama di semua unit terjemahan.
cppreference https://en.cppreference.com/w/cpp/language/inline menjelaskan bahwa jika static
tidak diberikan, maka ia memiliki tautan eksternal.
Penerapan variabel sebaris GCC
Kita dapat mengamati bagaimana ini diterapkan dengan:
nm main.o notmain.o
yang mengandung:
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
dan man nm
mengatakan tentang u
:
"u" Simbolnya adalah simbol global yang unik. Ini adalah ekstensi GNU untuk set standar binding simbol ELF. Untuk simbol seperti itu, dynamic linker akan memastikan bahwa dalam keseluruhan proses hanya ada satu simbol dengan nama dan tipe ini yang digunakan.
jadi kami melihat bahwa ada ekstensi ELF khusus untuk ini.
Pra-C ++ 17: extern const
Sebelum C ++ 17, dan di C, kita dapat mencapai efek yang sangat mirip dengan sebuah extern const
, yang akan mengarah ke satu lokasi memori yang digunakan.
Kerugiannya inline
adalah:
- tidak mungkin membuat variabel
constexpr
dengan teknik ini, hanya inline
memungkinkan: Bagaimana cara mendeklarasikan constexpr extern?
- ini kurang elegan karena Anda harus mendeklarasikan dan mendefinisikan variabel secara terpisah di file header dan 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 upstream .
Alternatif header saja Pre-C ++ 17
Ini tidak sebaik extern
solusinya, tetapi berfungsi dan hanya menggunakan satu lokasi memori:
Sebuah constexpr
fungsi, karena constexpr
menyiratkaninline
dan inline
memungkinkan (memaksa) definisi tersebut muncul di setiap unit terjemahan :
constexpr int shared_inline_constexpr() { return 42; }
dan saya yakin bahwa setiap kompilator yang layak akan melakukan panggilan inline.
Anda juga dapat menggunakan variabel integer const
atau constexpr
statis seperti di:
#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;
}
tetapi Anda tidak dapat melakukan hal-hal seperti mengambil alamatnya, atau menjadi digunakan odr, lihat juga: https://en.cppreference.com/w/cpp/language/static "Anggota statis konstan" dan Menentukan data statis constexpr anggota
C
Dalam C situasinya sama dengan C ++ sebelum C ++ 17, saya telah mengunggah contoh di: Apa artinya "statis" di C?
Satu-satunya perbedaan adalah bahwa dalam C ++, const
menyiratkan static
untuk GLOBALS, tapi tidak di C: C ++ semantik `const` statis vs` const`
Adakah cara untuk membuatnya sebaris sepenuhnya?
TODO: apakah ada cara untuk menyebariskan variabel sepenuhnya, tanpa menggunakan memori sama sekali?
Mirip seperti yang dilakukan preprocessor.
Ini akan membutuhkan entah bagaimana:
- melarang atau mendeteksi jika alamat variabel diambil
- menambahkan informasi tersebut ke file objek ELF, dan biarkan LTO mengoptimalkannya
Terkait:
Diuji di Ubuntu 18.10, GCC 8.2.0.
const
.