“Daftarkan” kata kunci dalam C?

273

Apa yang dilakukan registerkata kunci dalam bahasa C? Saya telah membaca bahwa ini digunakan untuk mengoptimalkan tetapi tidak didefinisikan dengan jelas dalam standar apa pun. Apakah masih relevan dan jika demikian, kapan Anda akan menggunakannya?

Nick Van Brunt
sumber
42
Apa yang dilakukan kata kunci register di C? akan diabaikan :)
bestsss
19
@bestsss Tidak sepenuhnya diabaikan. Cobalah untuk mendapatkan alamat registervariabel.
qrdl
4
Kode yang Anda baca adalah youtube.com/watch?v=ibF36Yyeehw#t=1827 yang lama
Kolonel Panic

Jawaban:

341

Ini adalah petunjuk bagi kompiler bahwa variabel akan banyak digunakan dan Anda merekomendasikannya disimpan dalam register prosesor jika memungkinkan.

Kebanyakan kompiler modern melakukannya secara otomatis, dan lebih baik dalam memilih mereka daripada kita manusia.

Brian Knoblauch
sumber
18
Yah, saya bereksperimen dengan mendaftar untuk mendapatkan kiriman ACM saya tweak, dan kadang-kadang itu sangat membantu. Tetapi Anda benar-benar harus waspada, karena pilihan yang buruk menurunkan kinerja.
ypnos
81
Alasan yang baik untuk tidak menggunakan 'register': Anda tidak dapat mengambil alamat dari variabel yang terdaftar sebagai 'register'
Adam Rosenfield
23
Perhatikan bahwa beberapa / banyak kompiler akan sepenuhnya mengabaikan kata kunci register (yang sepenuhnya legal).
Euro Micelli
5
ypnos: Sebenarnya kecepatan solusi untuk masalah ICM ACM lebih tergantung pada pilihan algoritma daripada pada optimasi mikro seperti itu. Batas waktu 5 detik biasanya cukup untuk solusi yang benar, terutama ketika menggunakan C bukan Java.
Joey
66
@ Euro: Anda mungkin tahu ini, tetapi hanya untuk menjadi eksplisit, kompiler diperlukan untuk mencegah alamat registervariabel diambil; ini adalah satu - satunya efek wajib dari registerkata kunci. Bahkan ini cukup untuk meningkatkan optimisasi, karena menjadi sepele untuk mengatakan bahwa variabel hanya dapat dimodifikasi dalam fungsi ini.
Dale Hagglund
69

Saya terkejut bahwa tidak ada yang menyebutkan bahwa Anda tidak dapat mengambil alamat variabel register, bahkan jika kompiler memutuskan untuk menyimpan variabel dalam memori daripada dalam register.

Jadi menggunakan registerAnda tidak menang apa-apa (kompiler tetap akan memutuskan sendiri di mana menempatkan variabel) dan kehilangan &operator - tidak ada alasan untuk menggunakannya.

qrdl
sumber
94
Sebenarnya ada alasan. Fakta bahwa Anda tidak dapat mengambil alamat variabel menghasilkan beberapa peluang optimasi: kompiler dapat membuktikan bahwa variabel tidak akan alias.
Alexandre C.
8
Kompiler terkenal mengerikan dalam membuktikan bahwa aliasing tidak terjadi dalam kasus nontrivial, jadi registerberguna untuk ini bahkan jika kompiler tidak memasukkannya ke dalam register.
Miles Rout
2
@AlexandreC, Miles, kompiler sama sekali OK untuk memeriksa apakah & diambil dari variabel di mana saja. Jadi terlepas dari kesulitan lain tentang mendeteksi alias, menyatakan kembali bahwa Anda tidak membeli apa pun. Ketika K + R pertama kali dibuat C, memang berguna untuk mengetahui sebelumnya bahwa & tidak akan digunakan, karena kompilator itu benar-benar membuat keputusan alokasi register untuk melihat deklarasi, sebelum melihat kode berikut. Itulah sebabnya larangan itu diberlakukan. Kata kunci 'daftar' pada dasarnya sudah usang sekarang.
greggo
25
Dengan logika constini juga menjadi tidak berguna karena tidak memenangkan apa pun, Anda hanya kehilangan kemampuan untuk mengubah variabel. registerdapat digunakan untuk memastikan tidak ada yang mengambil alamat variabel di masa depan tanpa berpikir. Saya tidak pernah punya alasan untuk menggunakannya register.
Tor Klingberg
34

Ini memberitahu kompiler untuk mencoba menggunakan register CPU, bukan RAM, untuk menyimpan variabel. Register ada di CPU dan jauh lebih cepat diakses daripada RAM. Tapi itu hanya saran untuk kompiler, dan mungkin tidak bisa ditindaklanjuti.

Andrew Barnett
sumber
8
Layak ditambahkan untuk orang-orang yang menggunakan C ++, C ++ memungkinkan Anda mengambil alamat variabel register
Will
5
@ Will: ... tapi sebagai kompiler kemungkinan besar akan mengabaikan kata kunci. Lihat jawaban saya.
bwDraco
Ya, tampaknya 'daftar' adalah plasebo dalam C ++, itu hanya ada untuk memungkinkan kode C dikompilasi sebagai C ++. Dan tidak masuk akal untuk melarang & var sambil mengizinkan melewatinya dengan referensi, atau const-reference, dan tanpa pass-by-reference Anda telah benar-benar melanggar C ++.
greggo
22

Saya tahu pertanyaan ini tentang C, tetapi pertanyaan yang sama untuk C ++ ditutup sebagai duplikat yang tepat dari pertanyaan ini. Karena itu jawaban ini mungkin tidak berlaku untuk C.


Draf terbaru standar C ++ 11, N3485 , mengatakan ini dalam 7.1.1 / 3:

Sebuah registerspecifier adalah petunjuk untuk implementasi bahwa variabel yang dideklarasikan akan banyak digunakan. [ catatan: Petunjuk dapat diabaikan dan di sebagian besar implementasi akan diabaikan jika alamat variabel diambil. Penggunaan ini sudah usang ... —kirim catatan ]

Dalam C ++ (tetapi tidak dalam C), standar tidak menyatakan bahwa Anda tidak dapat mengambil alamat variabel yang dideklarasikan register; Namun, karena variabel yang disimpan dalam register CPU sepanjang masa hidupnya tidak memiliki lokasi memori yang terkait dengannya, upaya untuk mengambil alamatnya tidak valid, dan kompiler akan mengabaikan registerkata kunci untuk mengizinkan pengambilan alamat.

bwDraco
sumber
17

Belum relevan selama setidaknya 15 tahun karena pengoptimal membuat keputusan yang lebih baik tentang ini daripada yang Anda bisa. Bahkan ketika itu relevan, itu jauh lebih masuk akal pada arsitektur CPU dengan banyak register, seperti SPARC atau M68000 daripada di Intel dengan kekurangan register, sebagian besar yang disediakan oleh kompiler untuk keperluannya sendiri.

Paul Tomblin
sumber
13

Sebenarnya, register memberi tahu kompiler bahwa variabel tidak alias dengan hal lain dalam program (bahkan char).

Itu dapat dieksploitasi oleh kompiler modern dalam berbagai situasi, dan dapat membantu kompiler sedikit dalam kode kompleks - dalam kode sederhana kompiler dapat mengetahui hal ini sendiri.

Kalau tidak, itu tidak ada gunanya dan tidak digunakan untuk alokasi register. Biasanya tidak menyebabkan penurunan kinerja untuk menentukannya, selama kompiler Anda cukup modern.

Rupert
sumber
"Memberitahu kompiler .." tidak, tidak. Semua variabel otomatis memiliki properti itu, kecuali jika Anda mengambil alamatnya dan menggunakannya dengan cara yang melebihi penggunaan tertentu yang dapat dianalisis. Jadi, kompiler mengetahui hal ini dari kode, terlepas dari apakah Anda menggunakan kata kunci register. Kebetulan kata kunci 'register' membuatnya ilegal untuk menulis konstruksi seperti itu, tetapi jika Anda tidak menggunakan kata kunci, dan jangan mengambil alamat sedemikian rupa, maka kompiler masih tahu itu aman. Informasi tersebut sangat penting untuk optimasi.
greggo
1
@greggo: Terlalu buruk registermelarang mengambil alamat sama sekali, karena jika tidak, akan berguna untuk memberi tahu kompiler kasus di mana kompiler akan dapat menerapkan optimasi register meskipun alamat variabel diteruskan ke fungsi eksternal (variabel harus dimasukkan ke memori untuk panggilan tertentu , tetapi begitu fungsi kembali, kompiler dapat kembali memperlakukannya sebagai variabel yang alamatnya tidak pernah diambil).
supercat
@supercat saya pikir masih akan menjadi percakapan yang sangat sulit untuk dilakukan dengan kompiler. Jika itu yang ingin Anda sampaikan kepada kompiler, Anda dapat melakukannya dengan menyalin variabel pertama ke variabel kedua yang tidak memiliki '&' di dalamnya, dan kemudian tidak pernah menggunakan yang pertama lagi.
greggo
1
@greggo: Mengatakan bahwa jika baradalah registervariabel, compiler mungkin di waktu luang nya ganti foo(&bar);dengan int temp=bar; foo(&temp); bar=temp;, tetapi mengambil alamat barakan dilarang di sebagian besar konteks lain tidak akan tampak seperti aturan yang terlalu rumit. Jika variabel bisa disimpan dalam register, substitusi akan membuat kode lebih kecil. Jika variabel tetap harus disimpan dalam RAM, substitusi akan membuat kode lebih besar. Membiarkan pertanyaan apakah membuat substitusi hingga kompiler akan menghasilkan kode yang lebih baik dalam kedua kasus.
supercat
1
@greggo: Mengizinkan registerkualifikasi pada variabel global, apakah kompiler mengizinkan alamat untuk diambil atau tidak, akan memungkinkan beberapa optimasi yang bagus dalam kasus-kasus di mana fungsi yang digariskan yang menggunakan variabel global disebut berulang kali dalam satu lingkaran. Saya tidak bisa memikirkan cara lain untuk membiarkan variabel itu disimpan dalam register antara iterasi loop - bisakah Anda?
supercat
13

Saya telah membaca bahwa ini digunakan untuk mengoptimalkan tetapi tidak didefinisikan dengan jelas dalam standar apa pun.

Faktanya, standar ini didefinisikan dengan jelas oleh standar C. Mengutip draft N1570 bagian 6.7.1 paragraf 6 (versi lain memiliki kata-kata yang sama):

Deklarasi pengidentifikasi untuk objek dengan specifier kelas penyimpanan registermenunjukkan bahwa akses ke objek secepat mungkin. Sejauh mana saran tersebut efektif ditentukan oleh implementasi.

&Operator unary tidak dapat diterapkan pada objek yang didefinisikan dengan register, dan registertidak dapat digunakan dalam deklarasi eksternal.

Ada beberapa aturan lain (cukup tidak jelas) yang khusus untuk registerobjek-berkualitas:

  • Mendefinisikan objek array dengan registerperilaku tidak terdefinisi.
    Koreksi: Adalah sah untuk mendefinisikan objek array register, tetapi Anda tidak dapat melakukan sesuatu yang berguna dengan objek semacam itu (pengindeksan ke dalam array memerlukan pengambilan alamat elemen awalnya).
  • The _Alignasspecifier (baru di C11) tidak dapat diterapkan ke objek tersebut.
  • Jika nama parameter yang diteruskan ke va_startmakro- registerterkualifikasi, perilaku tidak terdefinisi.

Mungkin ada beberapa yang lain; unduh konsep standar dan cari "daftar" jika Anda tertarik.

Seperti namanya, arti asliregister adalah untuk meminta objek disimpan dalam register CPU. Tetapi dengan perbaikan dalam mengoptimalkan kompiler, ini menjadi kurang bermanfaat. Versi modern dari standar C tidak merujuk ke register CPU, karena mereka tidak lagi (perlu) menganggap bahwa ada hal seperti itu (ada arsitektur yang tidak menggunakan register). Kebijaksanaan umum adalah bahwa menerapkan registerdeklarasi objek lebih cenderung memperburuk kode yang dihasilkan, karena itu mengganggu alokasi register kompilator sendiri. Mungkin masih ada beberapa kasus di mana itu berguna (katakanlah, jika Anda benar-benar tahu seberapa sering variabel akan diakses, dan pengetahuan Anda lebih baik daripada apa yang bisa diketahui oleh kompiler pengoptimal modern).

Efek nyata utama registeradalah mencegah setiap upaya untuk mengambil alamat objek. Ini tidak terlalu berguna sebagai petunjuk optimasi, karena hanya dapat diterapkan pada variabel lokal, dan kompilator pengoptimalisasi dapat melihat sendiri bahwa alamat objek seperti itu tidak diambil.

Keith Thompson
sumber
jadi apakah perilaku program ini benar-benar tidak terdefinisi sesuai dengan standar C? Apakah ini didefinisikan dengan baik dalam C ++? Saya pikir itu didefinisikan dengan baik dalam C ++.
Destructor
@Destructor: Mengapa itu tidak terdefinisi? Tidak ada registerobjek array yang memenuhi syarat, jika itu yang Anda pikirkan.
Keith Thompson
Oh maaf saya lupa menulis kata kunci register di deklarasi array di main (). Apakah ini didefinisikan dengan baik dalam C ++?
Destructor
Saya salah tentang mendefinisikan registerobjek array; lihat poin pertama yang diperbarui dalam jawaban saya. Adalah sah untuk mendefinisikan objek seperti itu, tetapi Anda tidak dapat melakukan apa pun dengannya. Jika Anda menambahkan registerdefinisi sdalam contoh Anda , program ini ilegal (pelanggaran kendala) dalam C. C ++ tidak menempatkan batasan yang sama register, sehingga program tersebut akan menjadi valid C ++ (tetapi menggunakan registerakan sia-sia).
Keith Thompson
@KeithThompson: Kata registerkunci dapat melayani tujuan yang berguna jika sah untuk mengambil alamat variabel seperti itu tetapi hanya dalam kasus di mana semantik tidak akan terpengaruh dengan menyalin variabel ke sementara ketika alamat diambil, dan memuat ulang dari sementara pada titik urutan berikutnya. Itu akan memungkinkan kompiler untuk berasumsi bahwa variabel dapat disimpan dengan aman di register di semua akses pointer asalkan itu memerah di setiap tempat alamatnya diambil.
supercat
9

Waktu cerita!

C, sebagai bahasa, adalah abstraksi komputer. Hal ini memungkinkan Anda untuk melakukan hal-hal, dalam hal apa yang dilakukan komputer, yaitu memanipulasi memori, melakukan matematika, mencetak sesuatu, dll.

Tetapi C hanyalah abstraksi. Dan akhirnya, apa yang diambil dari Anda adalah bahasa Assembly. Assembly adalah bahasa yang dibaca CPU, dan jika Anda menggunakannya, Anda melakukan hal-hal dalam hal CPU. Apa yang dilakukan CPU? Pada dasarnya, ia membaca dari memori, melakukan matematika, dan menulis ke memori. CPU tidak hanya menghitung angka dalam memori. Pertama, Anda harus memindahkan nomor dari memori ke memori di dalam CPU yang disebut register. Setelah selesai melakukan apa pun yang perlu Anda lakukan untuk nomor ini, Anda dapat memindahkannya kembali ke memori sistem normal. Mengapa menggunakan memori sistem sama sekali? Registrasi jumlahnya terbatas. Anda hanya mendapatkan sekitar seratus byte dalam prosesor modern, dan prosesor populer yang lebih tua bahkan lebih terbatas secara fantastis (The 6502 memiliki 3 register 8-bit untuk penggunaan gratis Anda). Jadi, operasi matematika rata-rata Anda seperti:

load first number from memory
load second number from memory
add the two
store answer into memory

Banyak dari itu ... bukan matematika. Operasi pemuatan dan penyimpanan tersebut dapat memakan waktu hingga setengah waktu pemrosesan Anda. C, sebagai abstraksi komputer, membebaskan programmer khawatir menggunakan dan menyulap register, dan karena jumlah dan jenis bervariasi antara komputer, C menempatkan tanggung jawab alokasi register hanya pada kompiler. Dengan satu pengecualian.

Saat Anda mendeklarasikan variabel register, Anda mengatakan kepada kompiler, "Yo, saya bermaksud agar variabel ini banyak digunakan dan / atau berumur pendek. Jika saya jadi Anda, saya akan mencoba menyimpannya dalam register." Ketika standar C mengatakan kompiler tidak harus benar-benar melakukan apa-apa, itu karena standar C tidak tahu komputer apa yang Anda kompilasi, dan mungkin seperti 6502 di atas, di mana ketiga register diperlukan hanya untuk mengoperasikan , dan tidak ada register cadangan untuk menyimpan nomor Anda. Namun, ketika dikatakan Anda tidak dapat mengambil alamat, itu karena register tidak memiliki alamat. Mereka adalah tangan prosesor. Karena kompiler tidak harus memberi Anda alamat, dan karena tidak dapat memiliki alamat sama sekali, beberapa optimasi sekarang terbuka untuk kompiler. Bisa, katakanlah, menyimpan nomor dalam register selalu. Tidak Anda tidak perlu khawatir tentang tempat penyimpanannya di memori komputer (di luar keharusan untuk mendapatkannya kembali). Bahkan bisa menghukumnya menjadi variabel lain, memberikannya ke prosesor lain, memberinya lokasi yang berubah, dll.

tl; dr: Variabel berumur pendek yang mengerjakan banyak matematika. Jangan mendeklarasikan terlalu banyak sekaligus.

Orion
sumber
5

Anda mengacaukan algoritma pewarnaan graf canggih dari kompiler. Ini digunakan untuk alokasi register. Yah, kebanyakan. Ini bertindak sebagai petunjuk untuk kompiler - itu benar. Tetapi jangan diabaikan secara keseluruhan karena Anda tidak diizinkan untuk mengambil alamat variabel register (ingat kompiler, sekarang pada belas kasihan Anda, akan mencoba untuk bertindak berbeda). Yang dengan cara memberitahu Anda untuk tidak menggunakannya.

Kata kunci itu digunakan lama sekali, panjang kembali. Ketika hanya ada sedikit register yang bisa menghitung semuanya menggunakan jari telunjuk Anda.

Tetapi, seperti yang saya katakan, usang tidak berarti Anda tidak dapat menggunakannya.

secara langsung
sumber
13
Beberapa perangkat keras yang lama memiliki register lebih banyak daripada mesin Intel modern. Jumlah register tidak ada hubungannya dengan usia dan semua yang berhubungan dengan arsitektur CPU.
HANYA SAYA PENDAPAT benar
2
@JUSTMYcorrectOPINION Memang, pada dasarnya X86 memiliki enam, semuanya paling banyak 1 atau 2 untuk dedikasi untuk 'mendaftar'. Bahkan, karena begitu banyak kode telah ditulis atau dipindahkan ke mesin register-miskin, saya menduga ini berkontribusi besar pada kata kunci 'register' menjadi plasebo - tidak ada gunanya mengisyaratkan register ketika tidak ada. Kita di sini 4+ tahun kemudian dan untungnya x86_64 telah meningkatkannya menjadi 14, dan ARM adalah hal yang besar sekarang juga.
greggo
4

Hanya sedikit demo (tanpa tujuan dunia nyata) untuk perbandingan: saat menghapus registerkata kunci sebelum setiap variabel, kode ini memakan waktu 3,41 detik pada i7 (GCC) saya, dengan register kode yang sama selesai dalam 0,7 detik.

#include <stdio.h>

int main(int argc, char** argv) {

     register int numIterations = 20000;    

     register int i=0;
     unsigned long val=0;

    for (i; i<numIterations+1; i++)
    {
        register int j=0;
        for (j;j<i;j++) 
        {
            val=j+i;
        }
    }
    printf("%d", val);
    return 0;
}
Alex
sumber
2
Dengan gcc 4.8.4 dan -O3, saya tidak mendapatkan perbedaan. Tanpa iterasi -O3 dan 40000, saya mungkin mendapatkan kurang dari 50 ms pada total waktu 1.5s, tapi saya tidak menjalankannya cukup waktu untuk mengetahui apakah itu bahkan signifikan secara statistik.
zstewart
Tidak ada perbedaan dengan CLANG 5.0, platform AMD64. (Saya sudah memeriksa output ASM.)
ern0
4

Saya telah menguji kata kunci register di bawah QNX 6.5.0 menggunakan kode berikut:

#include <stdlib.h>
#include <stdio.h>
#include <inttypes.h>
#include <sys/neutrino.h>
#include <sys/syspage.h>

int main(int argc, char *argv[]) {
    uint64_t cps, cycle1, cycle2, ncycles;
    double sec;
    register int a=0, b = 1, c = 3, i;

    cycle1 = ClockCycles();

    for(i = 0; i < 100000000; i++)
        a = ((a + b + c) * c) / 2;

    cycle2 = ClockCycles();
    ncycles = cycle2 - cycle1;
    printf("%lld cycles elapsed\n", ncycles);

    cps = SYSPAGE_ENTRY(qtime) -> cycles_per_sec;
    printf("This system has %lld cycles per second\n", cps);
    sec = (double)ncycles/cps;
    printf("The cycles in seconds is %f\n", sec);

    return EXIT_SUCCESS;
}

Saya mendapat hasil sebagai berikut:

-> 807679611 siklus berlalu

-> Sistem ini memiliki 3300830000 siklus per detik

-> Siklus dalam hitungan detik adalah ~ 0,244600

Dan sekarang tanpa register int:

int a=0, b = 1, c = 3, i;

Saya mendapatkan:

-> 1421694077 siklus telah berlalu

-> Sistem ini memiliki 3300830000 siklus per detik

-> Siklus dalam hitungan detik adalah ~ 0,430700

Daniel B
sumber
2

Mendaftar akan memberi tahu kompiler bahwa pembuat kode percaya bahwa variabel ini akan ditulis / dibaca cukup untuk membenarkan penyimpanannya di salah satu dari beberapa register yang tersedia untuk penggunaan variabel. Membaca / menulis dari register biasanya lebih cepat dan memerlukan set kode op yang lebih kecil.

Saat ini, ini tidak terlalu berguna, karena kebanyakan pengoptimal kompiler lebih baik daripada Anda dalam menentukan apakah register harus digunakan untuk variabel itu, dan untuk berapa lama.

billjamesdev
sumber
2

Selama tahun tujuh puluhan, pada awal bahasa C, kata kunci register telah diperkenalkan untuk memungkinkan programmer memberikan petunjuk kepada kompiler, mengatakan bahwa variabel akan digunakan sangat sering, dan bahwa itu harus bijaksana untuk simpan nilainya di salah satu register internal prosesor.

Saat ini, pengoptimal jauh lebih efisien daripada programmer untuk menentukan variabel yang lebih mungkin untuk disimpan dalam register, dan pengoptimal tidak selalu mempertimbangkan petunjuk programmer.

Jadi banyak orang salah merekomendasikan untuk tidak menggunakan kata kunci register.

Mari kita lihat alasannya!

Kata kunci register memiliki efek samping yang terkait: Anda tidak dapat merujuk (mendapatkan alamat) variabel tipe register.

Orang yang menyarankan orang lain untuk tidak menggunakan register menganggap ini sebagai argumen tambahan.

Namun, fakta sederhana mengetahui bahwa Anda tidak dapat mengambil alamat variabel register, memungkinkan kompiler (dan pengoptimalnya) mengetahui bahwa nilai variabel ini tidak dapat dimodifikasi secara tidak langsung melalui pointer.

Ketika pada titik tertentu dari aliran instruksi, variabel register memiliki nilainya yang ditetapkan dalam register prosesor, dan register tersebut belum digunakan karena untuk mendapatkan nilai variabel lain, kompiler tahu bahwa ia tidak perlu memuat ulang nilai variabel dalam register itu. Hal ini memungkinkan untuk menghindari akses memori mahal yang tidak berguna.

Lakukan tes Anda sendiri dan Anda akan mendapatkan peningkatan kinerja yang signifikan di loop batin Anda.

c_register_side_effect_performance_boost


sumber
1

Pada kompiler C yang didukung, ia mencoba untuk mengoptimalkan kode sehingga nilai variabel disimpan dalam register prosesor yang sebenarnya.

Dana Holt
sumber
1

Kompiler Visual C ++ Microsoft mengabaikan registerkata kunci ketika optimasi alokasi register global (flag / compiler Oe) diaktifkan.

Lihat mendaftar kata kunci di MSDN.

M. Dudley
sumber
1

Daftarkan kata kunci memberitahu kompiler untuk menyimpan variabel tertentu dalam register CPU sehingga dapat diakses dengan cepat. Dari sudut pandang programmer, kata kunci register digunakan untuk variabel yang banyak digunakan dalam suatu program, sehingga kompiler dapat mempercepat kode. Meskipun itu tergantung pada kompiler apakah akan menyimpan variabel dalam register CPU atau memori utama.

Sanjeev Kumar
sumber
0

Register menunjukkan kepada kompiler untuk mengoptimalkan kode ini dengan menyimpan variabel tertentu dalam register kemudian dalam memori. itu adalah permintaan untuk kompiler, kompiler mungkin atau mungkin tidak mempertimbangkan permintaan ini. Anda dapat menggunakan fasilitas ini jika beberapa variabel Anda sedang diakses sangat sering. Misalnya: Perulangan.

Satu hal lagi adalah bahwa jika Anda mendeklarasikan variabel sebagai register maka Anda tidak bisa mendapatkan alamatnya karena tidak disimpan dalam memori. itu mendapat alokasi dalam register CPU.

terbang tinggi
sumber
0

gcc 9.3 asm output, tanpa menggunakan flag optimisasi (semua yang ada dalam jawaban ini merujuk pada kompilasi standar tanpa flag optimisasi):

#include <stdio.h>
int main(void) {
  int i = 3;
  i++;
  printf("%d", i);
  return 0;
}
.LC0:
        .string "%d"
main:
        push    rbp
        mov     rbp, rsp
        sub     rsp, 16
        mov     DWORD PTR [rbp-4], 3
        add     DWORD PTR [rbp-4], 1
        mov     eax, DWORD PTR [rbp-4]
        mov     esi, eax
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        mov     eax, 0
        leave 
        ret
#include <stdio.h>
int main(void) {
  register int i = 3;
  i++;
  printf("%d", i);
  return 0;
}
.LC0:
        .string "%d"
main:
        push    rbp
        mov     rbp, rsp
        push    rbx
        sub     rsp, 8
        mov     ebx, 3
        add     ebx, 1
        mov     esi, ebx
        mov     edi, OFFSET FLAT:.LC0
        mov     eax, 0
        call    printf
        add     rsp, 8
        pop     rbx
        pop     rbp
        ret

Kekuatan ini ebxdigunakan untuk perhitungan, yang berarti perlu didorong ke stack dan dikembalikan pada akhir fungsi karena disimpan sementara. registermenghasilkan lebih banyak baris kode dan 1 memori tulis dan 1 memori dibaca (walaupun secara realistis, ini bisa dioptimalkan ke 0 R / Ws jika perhitungan telah dilakukan esi, yang adalah apa yang terjadi menggunakan C ++ 's const register). Tidak menggunakan registerpenyebab 2 tulis dan 1 baca (walaupun store to load forwarding akan terjadi pada baca). Ini karena nilainya harus ada dan diperbarui secara langsung pada tumpukan sehingga nilai yang benar dapat dibaca berdasarkan alamat (penunjuk). registertidak memiliki persyaratan ini dan tidak dapat diarahkan. constdan registerpada dasarnya kebalikan dari volatiledan menggunakanvolatileakan mengesampingkan optimisasi const pada ruang lingkup file dan blok dan registeroptimisasi pada ruang lingkup blok. const registerdan registerakan menghasilkan output yang identik karena const tidak melakukan apapun pada C pada block-scope, jadi hanya registeroptimisasi yang berlaku.

Pada dentang, registerdiabaikan tetapi constoptimisasi masih terjadi.

Lewis Kelsey
sumber