Anahtar kelimeyi C ++ 'da kaydedin


89

Arasındaki fark nedir

int x=7;

ve

register int x=7;

?

C ++ kullanıyorum.


8
@GMan: ANSI C, bir kayıt nesnesinin adresinin alınmasına izin vermez; bu kısıtlama C ++ için geçerli değildir
Brian R. Bondy

1
@Brian: Hm, haklısın. Sadece şimdi bir notta (adres alınırsa muhtemelen göz ardı edilecektir), ancak zorunlu değildir. Bunu bildiğim iyi oldu. (Pekala, bir çeşit: P)
GManNickG

8
Yeniden açma registeroylaması, C ve C ++ arasında farklı anlamlara sahiptir.
CB Bailey

3
Bunun bir sonucu olarak, C'de bir dizi kaydı yaparak diziden işaretçiye dönüşümün yasaklanması mümkündür: register int a[1];bu bildirimle, bu diziyi indeksleyemezsiniz.
Denerseniz

2
Doğrusu, yeniden açılmasına oy verdim. Bir fark olduğunu bilmeden önce kapatmaya oy verdim.
GManNickG

Yanıtlar:


24

2010'da olduğu gibi C ++ 'da, "otomatik" veya "kayıt" anahtar kelimelerini kullanan geçerli herhangi bir program, bu anahtar kelimeler kaldırılmış olanla semantik olarak aynı olacaktır (dizgeli makrolarda veya diğer benzer bağlamlarda görünmedikçe). Bu anlamda, anahtar kelimeler düzgün derlenen programlar için işe yaramaz. Öte yandan, bir makronun uygunsuz kullanımının sahte kod üretmek yerine derleme zamanı hatasına neden olmasını sağlamak için anahtar sözcükler belirli makro bağlamlarında yararlı olabilir.

C ++ 11 ve dilin sonraki sürümlerinde, autoanahtar sözcük, başlatılan nesneler için sözde tür olarak hareket etmek üzere yeniden amaçlanmıştır ve bir derleyici otomatik olarak başlatan ifadenin türüyle değiştirecektir. Bu nedenle, C ++ 03'te bildirim: bir blok bağlamı içinde kullanıldığında auto int i=(unsigned char)5;ile eşdeğerdi int i=5;ve auto i=(unsigned char)5;bir kısıtlama ihlaliydi. C ++ 11'de,auto int i=(unsigned char)5; ise bir kısıtlama ihlali haline auto i=(unsigned char)5;denk oldu auto unsigned char i=5;.


22
Son bitin bir örneği faydalı olabilir.
Dennis Zickefoose

14
Bu cevap artık doğru değil, 2011'den beri anahtar kelime autobasitçe ihmal edilemez ... Belki cevabınızı güncelleyebilirsiniz.
Walter

2
@Walter: Nelerin değiştiğinden bahsedebilir misin? Tüm dil değişikliklerini takip etmedim.
supercat

2
@supercat, şu an için evet, ancak registerkullanımdan kaldırıldı ve C ++ 17 için kaldırılması için bir teklif yapılacak.
Jonathan Wakely

3
En.cppreference.com/w/cpp/language/auto'ya göre , C ++ 11 sonrası autoartık otomatik tür çıkarımı için kullanılıyor. Ancak ondan önce, değişkeninizin "otomatik olarak" saklanmasını istediğinizi belirtmek için kullanıldı ( bu nedenle, sanırım yığında ) anahtar sözcüğün aksine register("işlemcinin kaydı" anlamına gelir):
Guillaume

96

register derleyiciye bu değişkeni bellek yerine bir işlemci kaydında saklamasını tavsiye eden bir ipucudur (örneğin, yığın yerine).

Derleyici bu ipucunu takip edebilir veya takip etmeyebilir.

Herb Sutter'a göre " Olmayan Anahtar Kelimeler (veya Başka İsimle Yapılan Yorumlar)" :

Bir kayıt belirticisi, bir otomatik belirtici ile aynı anlam bilgisine sahiptir ...


2
Ancak C ++ 17'den beri, kullanımdan kaldırılmış, kullanılmamış ve rezerve edilmiştir.
ZachB

@ZachB, bu yanlış; register C ++ 17'de saklıdır ancak yine de çalışır ve C'nin registerı ile hemen hemen aynı şekilde çalışır .
Lewis Kelsey

@LewisKelsey Kullanılmamış ve C ++ 17 spesifikasyonunda saklıdır; storage-class-specifierdilbilgisinde yer alanlardan biri değildir ve tanımlanmış bir semantiği yoktur. Uyumlu bir derleyici, Clang'ın yaptığı gibi bir hata atabilir. Yine de bazı uygulamalar buna izin veriyor ve ya yok sayıyor (MSVC, ICC) ya da bir optimizasyon ipucu (GCC) olarak kullanıyor. Open-std.org/jtc1/sc22/wg21/docs/papers/2015/p0001r1.html adresine bakın . Yine de bir noktada yanlış konuştum: C ++ 11'de kullanımdan kaldırıldı.
ZachB


25

Bugünün derleyicileriyle, muhtemelen hiçbir şey yok. Genellikle daha hızlı erişim için bir kayda bir değişken yerleştirmek için bir ipucuydu, ancak bugün çoğu derleyici bu ipucunu görmezden geliyor ve kendileri karar veriyor.


9

Neredeyse kesinlikle hiçbir şey.

registerderleyiciye xçok kullanmayı planladığınız ve bir kayıt defterine yerleştirilmesi gerektiğini düşündüğünüz bir ipucudur .

Ancak, derleyiciler artık kayıtlara hangi değerlerin yerleştirilmesi gerektiğini belirlemede ortalama (hatta uzman) bir programcının olduğundan çok daha iyidir, bu nedenle derleyiciler anahtar kelimeyi görmezden gelir ve istediklerini yapar.



7

registerAnahtar kelime için yararlı oldu:

  • Satır içi montaj.
  • Uzman C / C ++ programlama.
  • Önbelleğe alınabilir değişken beyanı.

registerAnahtar kelimenin gerekli olduğu verimli bir sistem örneği :

typedef unsigned long long Out;
volatile Out out,tmp;
Out register rax asm("rax");
asm volatile("rdtsc":"=A"(rax));
out=out*tmp+rax;

C ++ 11'den beri kullanımdan kaldırıldı ve kullanılmıyor ve C ++ 17'de saklanıyor .


2
Ve 'register' anahtar kelimesinin sadece tek bir C ++ programı çalıştıran ve çoklu görev içermeyen tek bir C ++ programı çalıştıran bir mikrodenetleyicide faydalı olacağını ekleyeceğim. C ++ programı, 'register' değişkeninin özel CPU kayıtlarından taşınmayacağından emin olmak için tüm CPU'ya sahip olmalıdır.
Santiago Villafuerte

@SantiagoVillafuerte yanıtı düzenleyerek eklemek ister misiniz?
ncomputers

Cevabımdan o kadar emin değilim ... inandırıcı gelse de. Başkalarının onaylaması veya onaylamaması için yorum olarak bırakmayı tercih ederim.
Santiago Villafuerte

1
@SantiagoVillafuerte Bu, çok görevli sistemlerde, kayıtların kaydedilmesinden / geri yüklenmesinden OS'yi bağlamdan değiştirirken - uygulama değil - gerçekten doğru değildir. Her CPU talimatından sonra bağlam değiştirme yapmadığınız için, şeyleri yazmaçlara koymak kesinlikle anlamlıdır. Buradaki diğer yanıtlar (derleyicilerin, kayıt ayırma kaydı söz konusu olduğunda fikrinizi önemsemediği) daha doğrudur.
Kübik

Gösterdiğiniz örnek, aslında GCC'nin , registerdepolama sınıfı belirticisinden farklı olan ve GCC tarafından hala desteklenen Explicit Register Variables uzantısını kullanıyor .
ZachB

2

Gcc 9.3'ten itibaren, kullanarak derleme -std=c++2a, register bir derleyici uyarısı üretir, ancak yine de istenen etkiye sahiptir ve bu yanıt registeraçısından -O1 –- olmadan derleme yaparken C'lere benzer şekilde davranır . Ancak clang ++ - 7 kullanımı bir derleyici hatasına neden olur. Yani evet,register optimizasyonlar sadece optimizasyon -O işaretleri olmadan standart derlemede bir fark yaratır, ancak bunlar derleyicinin -O1 ile bile anlayacağı temel optimizasyonlardır.

Tek fark, C ++ 'da, kayıt değişkeninin adresini almanıza izin verilmesidir; bu, optimizasyonun yalnızca değişkenin adresini veya takma adlarını (bir işaretçi oluşturmak için) veya bir referans almadığınızda gerçekleşeceği anlamına gelir. kodda (sadece - O0, çünkü bir referansın da bir adresi vardır, çünkü bu , -Ofast kullanarak derleme yapılıyorsa yığının dışında bir işaretçi gibi optimize edilebilen bir işaretçi gibi bir sabit işaretçisidir , ancak hiçbir zaman görünmezler) -Ofast kullanarak yığında, çünkü bir göstericinin aksine, yapılamazlar volatileve adresleri alınamaz), aksi takdirde kullanmamış gibi davranacaktırregister ve değer yığın üzerinde saklanacaktır.

-O0'da diğer bir fark, const registergcc C ve gcc C ++ 'da aynı şekilde davranmaz. Gcc C'de şu şekilde const registerdavranır register, çünkü blok kapsamları constgcc üzerinde optimize edilmemiştir. Clang C'de registerhiçbir şey yapmaz ve yalnızca constblok kapsamı optimizasyonları geçerlidir. Gcc C'de registeroptimizasyonlar geçerlidir ancak constblok kapsamında optimizasyon yoktur. Gcc C üzerinde ++, hem registerve constblok-kapsam optimisations birleştirir.

#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

registerderleyiciye 1) yerel bir değişkeni, bu durumda aranan uca kaydedilmiş bir kayıtta saklamasını rbxve 2) değişken adresi hiçbir zaman alınmazsa yığın yazmalarını optimize etmesini söyler . constderleyiciye değeri hemen değiştirmesini (ona bir kayıt atamak veya bellekten yüklemek yerine) ve yerel değişkeni varsayılan davranış olarak yığına yazmasını söyler .const registerbu cesaretlendirilmiş optimizasyonların birleşimidir. Bu olabildiğince ince.

Ayrıca, gcc C ve C ++ üzerinde, yığındaki ilk yerel için yığın registerüzerinde kendi başına rastgele 16 baytlık bir boşluk yaratıyor gibi görünüyor , bu daconst register .

Ancak -Ofast kullanarak derleme; register0 optimizasyon etkisine sahiptir, çünkü bir sicile koyulabilir veya anında yapılabilirse, her zaman olacaktır ve olamazsa olmayacak; constyine de C ve C ++ üzerindeki yükü optimize eder, ancak yalnızca dosya kapsamında ; volatileyine de değerleri yığından depolanmaya ve yüklenmeye zorlar.

.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

1

Derleyicinin iyileştiricisinin iki değişkene sahip olduğu ve birini yığına dökmeye zorlandığı bir durumu düşünün. Öyle oldu ki, her iki değişken de derleyici için aynı ağırlığa sahip. Fark olmadığı için, derleyici değişkenlerden birini keyfi olarak yayacaktır. Öte yandan,register anahtar kelime derleyiciye hangi değişkene daha sık erişileceği konusunda ipucu verir. X86 önceden getirme talimatına benzer, ancak derleyici iyileştirici içindir.

Açıkça register ipuçları, kullanıcı tarafından sağlanan dallanma olasılığı ipuçlarına benzer ve bu olasılık ipuçlarından çıkarılabilir. Derleyici bazı dalların sıklıkla alındığını bilirse, dalla ilgili değişkenleri kayıtlarda tutacaktır. Bu yüzden dal ipuçlarını daha fazla önemsemenizi ve unutmayı öneriyorum register. İdeal olarak profil uzmanınız derleyiciyle bir şekilde iletişim kurmalı ve sizi bu tür nüanslar hakkında düşünmekten bile kurtarmalıdır.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.