C ++ 17 inline
değişkenler
Google'da "C ++ const static" yazdıysanız, gerçekten kullanmak istediğiniz şey büyük olasılıkla C ++ 17 satır içi değişkenlerdir .
Bu harika C ++ 17 özelliği şunları yapmamızı sağlar:
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;
}
Derleyin ve çalıştırın:
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 yukarı akış .
Ayrıca bkz: Satır içi değişkenler nasıl çalışır?
Satır içi değişkenlerde C ++ standardı
C ++ standardı, adreslerin aynı olacağını garanti eder. C ++ 17 N4659 standart taslak
10.1.6 "Satır içi tanımlayıcı ":
6 Dış bağlantılı bir satır içi işlev veya değişken, tüm çeviri birimlerinde aynı adrese sahip olmalıdır.
cppreference https://en.cppreference.com/w/cpp/language/inline , static
verilmezse, harici bağlantıya sahip olduğunu açıklar .
GCC satır içi değişken uygulaması
Nasıl uygulandığını şu şekilde gözlemleyebiliriz:
nm main.o notmain.o
içerenler:
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
ve man nm
şöyle diyor u
:
"u" Sembol, benzersiz bir küresel semboldür. Bu, standart ELF simge bağlamaları kümesinin bir GNU uzantısıdır. Böyle bir sembol için dinamik bağlayıcı, tüm süreçte bu isim ve türe sahip tek bir sembolün kullanımda olduğundan emin olacaktır.
bu yüzden bunun için özel bir ELF uzantısı olduğunu görüyoruz.
Ön-C ++ 17: extern const
C ++ 17'den önce ve C'de, bir ile çok benzer bir etki elde edebiliriz extern const
, bu da tek bir bellek konumunun kullanılmasına yol açar.
Olumsuz yönler inline
:
- değişkeni
constexpr
bu teknikle yapmak mümkün değildir , sadece şunainline
izin verir: constexpr extern nasıl bildirilir?
- değişkeni başlık ve cpp dosyasında ayrı ayrı bildirmeniz ve tanımlamanız gerektiğinden daha az zariftir
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 yukarı akış .
Pre-C ++ 17 yalnızca başlık alternatifleri
Bunlar extern
çözüm kadar iyi değil , ancak işe yarıyor ve yalnızca tek bir bellek konumunu kaplıyor:
Bir constexpr
işlev, çünkü tanımın her çeviri biriminde görünmesini constexpr
ima ederinline
ve buna inline
izin verir (zorlar) :
constexpr int shared_inline_constexpr() { return 42; }
ve eminim ki herhangi bir düzgün derleyici çağrıyı sıraya dizecektir.
Ayrıca aşağıdaki gibi bir const
veya constexpr
statik değişken de kullanabilirsiniz :
#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;
}
ancak adresini almak gibi şeyler yapamazsınız, aksi takdirde odr kullanılır hale gelir, ayrıca bakınız: constexpr statik veri üyelerini tanımlama
C
C'de durum C ++ ön C ++ 17 ile aynıdır, şuraya bir örnek yükledim: C'de "statik" ne anlama geliyor?
Tek fark, C ++ ' const
da static
küreselleri ifade etmesidir, ancak C: C ++' statik sabit 've' sabit 'anlambilimlerinde yoktur.
Tamamen satır içi yapmanın bir yolu var mı?
TODO: Herhangi bir bellek kullanmadan değişkeni tam olarak satır içi yapmanın bir yolu var mı?
Önişlemcinin yaptığı gibi.
Bu bir şekilde şunları gerektirir:
- değişkenin adresi alınırsa yasaklamak veya tespit etmek
- bu bilgiyi ELF nesne dosyalarına ekleyin ve LTO'nun bunu optimize etmesine izin verin
İlişkili:
Ubuntu 18.10, GCC 8.2.0'da test edilmiştir.