Apa perbedaan antara
int x=7;
dan
register int x=7;
?
Saya menggunakan C ++.
Apa perbedaan antara
int x=7;
dan
register int x=7;
?
Saya menggunakan C ++.
registermemiliki semantik yang berbeda antara C dan C ++.
register int a[1];dengan deklarasi itu, Anda tidak dapat mengindeks array itu. Jika Anda mencoba, Anda melakukan UB
Jawaban:
Dalam C ++ seperti yang ada pada tahun 2010, program apa pun yang valid yang menggunakan kata kunci "auto" atau "register" akan identik secara semantik dengan kata kunci tersebut yang dihapus (kecuali jika program tersebut muncul dalam makro bersangkai atau konteks serupa lainnya). Dalam arti kata kunci tidak berguna untuk program kompilasi dengan benar. Di sisi lain, kata kunci mungkin berguna dalam konteks makro tertentu untuk memastikan bahwa penggunaan makro yang tidak tepat akan menyebabkan kesalahan waktu kompilasi daripada menghasilkan kode palsu.
Di C ++ 11 dan versi bahasa yang lebih baru, autokata kunci itu bertujuan ulang untuk bertindak sebagai pseudo-type untuk objek yang diinisialisasi, yang secara otomatis akan diganti oleh compiler dengan jenis ekspresi inisialisasi. Jadi, di C ++ 03, deklarasi: auto int i=(unsigned char)5;setara dengan int i=5;saat digunakan dalam konteks blok, dan auto i=(unsigned char)5;merupakan pelanggaran batasan. Di C ++ 11, auto int i=(unsigned char)5;menjadi pelanggaran kendala sementara auto i=(unsigned char)5;menjadi setara dengan auto unsigned char i=5;.
autotidak dapat dihilangkan begitu saja ... Mungkin Anda dapat memperbarui jawaban Anda.
registertidak digunakan lagi dan akan ada proposal untuk menghapusnya untuk C ++ 17.
autosekarang digunakan untuk pengurangan tipe otomatis. Namun sebelumnya, ini digunakan untuk menentukan bahwa Anda ingin variabel Anda disimpan "secara otomatis" ( oleh karena itu pada tumpukan saya kira) sebagai lawan dari kata kunci register(artinya "register prosesor"):
register adalah petunjuk bagi kompilator, yang menyarankannya untuk menyimpan variabel itu dalam register prosesor dan bukan memori (misalnya, alih-alih tumpukan).
Kompilator mungkin atau mungkin tidak mengikuti petunjuk itu.
Menurut Herb Sutter dalam "Kata Kunci yang Tidak (atau, Komentar oleh Nama Lain)" :
Penentu register memiliki semantik yang sama dengan penentu otomatis ...
storage-class-specifiertata bahasa dan tidak memiliki semantik yang ditentukan. Kompiler yang sesuai dapat menampilkan kesalahan seperti yang dilakukan Clang. Meskipun demikian, beberapa implementasi masih mengizinkannya dan mengabaikannya (MSVC, ICC) atau menggunakannya sebagai petunjuk pengoptimalan (GCC). Lihat open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0001r1.html . Saya memang salah bicara pada satu hal: itu tidak digunakan lagi di C ++ 11.
Menurut Herb Sutter , register" sama berartinya dengan spasi " dan tidak berpengaruh pada semantik program C ++.
Hampir pasti tidak ada.
registeradalah petunjuk bagi kompiler bahwa Anda berencana untuk xbanyak menggunakannya , dan menurut Anda itu harus ditempatkan dalam register.
Namun, compiler sekarang jauh lebih baik dalam menentukan nilai apa yang harus ditempatkan di register daripada programmer rata-rata (atau bahkan ahli), jadi compiler mengabaikan kata kunci, dan melakukan apa yang mereka inginkan.
registertidak digunakan lagi di C ++ 11. Ini tidak digunakan dan dicadangkan dalam C ++ 17.
Kata registerkunci itu berguna untuk:
Contoh sistem produktif, di mana registerkata kunci diperlukan:
typedef unsigned long long Out;
volatile Out out,tmp;
Out register rax asm("rax");
asm volatile("rdtsc":"=A"(rax));
out=out*tmp+rax;
Ini sudah tidak digunakan lagi sejak C ++ 11 dan tidak digunakan serta dicadangkan di C ++ 17 .
registerpenentu kelas penyimpanan dan masih didukung oleh GCC.
Mulai gcc 9.3, mengompilasi menggunakan -std=c++2a, register menghasilkan peringatan compiler, tetapi masih memiliki efek yang diinginkan dan berperilaku identik dengan C registerketika mengompilasi tanpa flag -O1 –- Optimasi Ofast sehubungan dengan jawaban ini . Namun, penggunaan clang ++ - 7 menyebabkan kesalahan kompiler. Jadi ya, registerpengoptimalan hanya membuat perbedaan pada kompilasi standar tanpa tanda pengoptimalan -O, tetapi pengoptimalan tersebut adalah pengoptimalan dasar yang akan diketahui oleh compiler bahkan dengan -O1.
Satu-satunya perbedaan adalah bahwa di C ++, Anda diizinkan untuk mengambil alamat dari variabel register yang berarti bahwa pengoptimalan hanya terjadi jika Anda tidak mengambil alamat variabel atau aliasnya (untuk membuat pointer) atau mengambil referensi di kode (hanya di - O0, karena referensi juga memiliki alamat, karena ini adalah pointer const di tumpukan , yang, seperti pointer dapat dioptimalkan dari tumpukan jika mengompilasi menggunakan -Ofast, kecuali mereka tidak akan pernah muncul pada stack menggunakan -Ofast, karena tidak seperti pointer, mereka tidak dapat dibuat volatiledan alamatnya tidak dapat diambil), jika tidak maka akan berperilaku seperti Anda tidak pernah menggunakannya register, dan nilainya akan disimpan di stack.
Pada -O0, perbedaan lainnya adalah const registerpada gcc C dan gcc C ++ tidak berperilaku sama. Di gcc C, const registerberperilaku seperti register, karena block-scope consts tidak dioptimalkan di gcc. Pada clang C, registertidak melakukan apa-apa dan hanya constpengoptimalan cakupan blok yang berlaku. Di gcc C, registerpengoptimalan diterapkan tetapi constdi block-scope tidak ada pengoptimalan. Di gcc C ++, pengoptimalan cakupan blok registerdan keduanya constdigabungkan.
#include <stdio.h> //yes it's C code on C++
int main(void) {
const register int i = 3;
printf("%d", i);
return 0;
}
int i = 3;:
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 3
mov eax, DWORD PTR [rbp-4]
mov esi, eax
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
register int i = 3;:
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
push rbx
sub rsp, 8
mov ebx, 3
mov esi, ebx
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
mov rbx, QWORD PTR [rbp-8] //callee restoration
leave
ret
const int i = 3;
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
sub rsp, 16
mov DWORD PTR [rbp-4], 3 //still saves to stack
mov esi, 3 //immediate substitution
mov edi, OFFSET FLAT:.LC0
mov eax, 0
call printf
mov eax, 0
leave
ret
const register int i = 3;
.LC0:
.string "%d"
main:
push rbp
mov rbp, rsp
mov esi, 3 //loads straight into esi saving rbx push/pop and extra indirection (because C++ block-scope const is always substituted immediately into the instruction)
mov edi, OFFSET FLAT:.LC0 // can't optimise away because printf only takes const char*
mov eax, 0 //zeroed: https://stackoverflow.com/a/6212755/7194773
call printf
mov eax, 0 //default return value of main is 0
pop rbp //nothing else pushed to stack -- more efficient than leave (rsp == rbp already)
ret
registermemberitahu compiler untuk 1) menyimpan variabel lokal dalam register yang disimpan callee, dalam hal ini rbx, dan 2) mengoptimalkan stack menulis jika alamat variabel tidak pernah diambil . constmemberi tahu compiler untuk segera mengganti nilai (alih-alih menetapkannya sebagai register atau memuatnya dari memori) dan menulis variabel lokal ke stack sebagai perilaku default. const registeradalah kombinasi dari pengoptimalan yang berani ini. Ini sangat tipis.
Selain itu, di gcc C dan C ++, registerdengan sendirinya tampaknya membuat celah 16 byte acak pada tumpukan untuk lokal pertama di tumpukan, yang tidak terjadi dengan const register.
Namun kompilasi menggunakan -Ofast; registermemiliki 0 efek optimasi karena jika bisa dimasukkan ke dalam register atau dibuat langsung, akan selalu begitu dan jika tidak bisa tidak akan; constmasih mengoptimalkan beban pada C dan C ++ tetapi hanya pada cakupan file ; volatilemasih memaksa nilai untuk disimpan dan dimuat dari tumpukan.
.LC0:
.string "%d"
main:
//optimises out push and change of rbp
sub rsp, 8 //https://stackoverflow.com/a/40344912/7194773
mov esi, 3
mov edi, OFFSET FLAT:.LC0
xor eax, eax //xor 2 bytes vs 5 for mov eax, 0
call printf
xor eax, eax
add rsp, 8
ret
Pertimbangkan kasus ketika pengoptimal kompiler memiliki dua variabel dan dipaksa untuk menumpahkan satu variabel ke tumpukan. Kebetulan kedua variabel tersebut memiliki bobot yang sama untuk compiler. Mengingat tidak ada perbedaan, compiler akan secara sewenang-wenang menumpahkan salah satu variabel. Di sisi lain, registerkata kunci memberi kompiler petunjuk variabel mana yang akan lebih sering diakses. Ini mirip dengan instruksi prefetch x86, tetapi untuk pengoptimal compiler.
Jelas registerpetunjuk mirip dengan petunjuk probabilitas cabang yang diberikan pengguna, dan bisa disimpulkan dari petunjuk probabilitas ini. Jika kompilator mengetahui bahwa beberapa cabang sering diambil, itu akan menyimpan variabel terkait cabang dalam register. Jadi saya sarankan untuk lebih memperhatikan petunjuk cabang, dan melupakannya register. Idealnya profiler Anda harus berkomunikasi dengan kompiler dan menghindarkan Anda dari pemikiran tentang nuansa seperti itu.