register
Anahtar kelime C dilinde ne yapar ? Optimizasyon için kullanıldığını ancak herhangi bir standartta açıkça tanımlanmadığını okudum. Hâlâ alakalı mı ve öyleyse ne zaman kullanırsınız?
register
Değişkenin adresini bulmaya çalışın .
register
Anahtar kelime C dilinde ne yapar ? Optimizasyon için kullanıldığını ancak herhangi bir standartta açıkça tanımlanmadığını okudum. Hâlâ alakalı mı ve öyleyse ne zaman kullanırsınız?
register
Değişkenin adresini bulmaya çalışın .
Yanıtlar:
Derleyiciye değişkenin yoğun bir şekilde kullanılacağına ve mümkünse bir işlemci kaydında tutulmasını öneriyoruz.
Çoğu modern derleyici bunu otomatik olarak yapar ve onları seçmekten biz insanlardan daha iyidir.
register
değişkenin adresinin alınmasını önlemek için derleyicinin bulunması gerekir ; bu sadece zorunlu etkisi register
anahtar kelime. Bu bile optimizasyonları iyileştirmek için yeterlidir, çünkü değişkenin sadece bu fonksiyon içinde değiştirilebileceğini söylemek önemsiz hale gelir.
Derleyici kayıttan ziyade değişkeni bellekte tutmaya karar verse bile, hiç kimse kayıt değişkeninin adresini alamayacağınızı söylemediğine şaşırdım.
Yani register
size hiçbir şey kazanmak (neyse derleyici değişkeni nereye koyacağına kendisi karar verir) ve &
operatörü kaybetmek - kullanmak için bir neden yok.
register
derleyici bir kayıt defterine koymasa bile bunun için yararlıdır.
const
, size hiçbir şey kazanmadığı için de işe yaramaz, sadece bir değişkeni değiştirme yeteneğini kaybedersiniz. register
gelecekte hiç kimsenin bir değişkenin adresini düşünmeden almasını sağlamak için kullanılabilir. register
Yine de kullanmak için hiçbir neden yoktu .
Derleyiciye, değişkeni saklamak için RAM yerine bir CPU kaydı kullanmayı denemesini söyler. Kayıtlar CPU'da ve erişim RAM'den çok daha hızlı. Ancak bu sadece derleyiciye bir öneridir ve takip etmeyebilir.
Bu sorunun C ile ilgili olduğunu biliyorum, ancak C ++ için aynı soru bu sorunun tam bir kopyası olarak kapatıldı. Dolayısıyla bu cevap C için geçerli olmayabilir.
C ++ 11 standardının son taslağı N3485 , 7.1.1 / 3'te bunu söylüyor:
Bir
register
tanımlayıcı, uygulamaya bu şekilde bildirilen değişkenin yoğun bir şekilde kullanılacağına dair bir ipucudur. [ not: İpucu yok sayılabilir ve çoğu uygulamada değişkenin adresi alınırsa yok sayılır. Bu kullanım kullanımdan kaldırıldı ... —end not ]
C ++ 'da (ancak C değil ), standart, bildirilen bir değişkenin adresini alamayacağınızı belirtmez register
; ancak, bir CPU kaydında depolanan bir değişkenin ömrü boyunca kendisiyle ilişkilendirilmiş bir bellek konumu olmadığından, adresini almaya çalışmak geçersiz olur ve derleyici register
, adresin alınmasına izin vermek için anahtar kelimeyi yoksayar .
Optimize ediciler bu konuda yapabileceğinizden daha iyi kararlar verdiklerinden, en az 15 yıldır geçerli değildir. İlgili olduğunda bile, SPARC veya M68000 gibi çok sayıda kayıt içeren bir CPU mimarisinde, çoğu derleyici tarafından kendi amaçları için ayrılmış olan kayıtların azlığıyla Intel'den çok daha mantıklıydı.
Aslında register, derleyiciye değişkenin programdaki herhangi bir şeyle takma olmadığını söyler (char'ın bile değil).
Bu, çeşitli durumlarda modern derleyiciler tarafından kullanılabilir ve derleyiciye karmaşık kodda biraz yardımcı olabilir - basit kodda derleyiciler bunu kendi başlarına çözebilir.
Aksi takdirde hiçbir amaca hizmet etmez ve kayıt tahsisi için kullanılmaz. Derleyiciniz yeterince modern olduğu sürece, bunu belirtmek genellikle performans düşüşüne neden olmaz.
register
Adresi almayı çok kötü yasaklar, aksi takdirde bir değişkenin adresinin harici bir işleve geçmesine rağmen bir derleyicinin kayıt optimizasyonlarını uygulayabileceği durumları bildirmesi yararlı olabilir (değişken belirli bir çağrı için belleğe boşaltılabilir , ancak işlev geri döndüğünde, derleyici tekrar adresi hiç alınmamış bir değişken olarak ele alabilir).
bar
bir olan register
değişken bir derleyici onun boş olabilir yerini foo(&bar);
ile int temp=bar; foo(&temp); bar=temp;
ancak adresini alarak bar
aşırı karmaşık bir kural gibi görünebilir olmaz en başka bağlamlarda yasak olacaktır. Değişken başka türlü bir kayıt defterinde tutulabiliyorsa, ikame kodu daha küçük hale getirecektir. Değişkenin yine de RAM'de tutulması gerekirse, ikame kodu daha büyük hale getirir. Değişikliğin derleyiciye yapılıp yapılmayacağı sorusunu bırakmak her iki durumda da daha iyi kodlamaya yol açacaktır.
register
Derleyicinin adresin alınmasına izin verip vermemesine bakılmaksızın, global değişkenler üzerinde bir kalifikasyona izin vermek , bir global değişken kullanan satır içi bir işlevin bir döngü içinde tekrar tekrar çağrılması durumunda bazı hoş optimizasyonlara izin verir. Ben bu değişken döngü yinelemeleri arasında bir kayıt tutulması için başka bir yol düşünemiyorum - değil mi?
Optimizasyon için kullanıldığını ancak herhangi bir standartta açıkça tanımlanmadığını okudum.
Aslında olduğu net bir şekilde Cı standardında tanımlandığı gibidir. N1570 taslak bölüm 6.7.1 paragraf 6'dan alıntı yapılması (diğer sürümler aynı ifadeye sahiptir):
Depolama sınıfı belirleyicisine sahip bir nesne için tanımlayıcı bildirimi, nesneye
register
erişimin mümkün olduğunca hızlı olmasını önerir. Bu tür önerilerin ne kadar etkili olduğu uygulama tanımlıdır.
Tekli &
operatör register
, ve ile tanımlanan bir nesneye uygulanamaz.register
harici bir bildirimde kullanılamaz.
register
Nitelikli nesnelere özgü birkaç (oldukça belirsiz) kural vardır :
register
tanımlanamayan bir davranışı var. register
, ancak böyle bir nesne ile yararlı bir şey yapamazsınız (bir dizine dizin oluşturmak, ilk öğesinin adresini almayı gerektirir)._Alignas
(C11 yeni) belirteci böyle bir nesne için uygulanamaz.va_start
Makroya iletilen parametre adı register
-kalifiye ise, davranış tanımsızdır.Birkaç tane daha olabilir; standardın taslağını indirin ve ilgileniyorsanız "kayıt ol" terimini arayın.
Adından da anlaşılacağı gibi, asıl anlamı, register
bir nesnenin CPU kaydında saklanmasını gerektiriyordu. Ancak derleyicilerin optimize edilmesindeki iyileştirmelerle, bu daha az kullanışlı hale geldi. C standardının modern versiyonları CPU kayıtlarına değinmez, çünkü artık böyle bir şey olduğunu varsaymazlar (buna gerek yoktur) (kayıt kullanmayan mimariler vardır). Ortak bilgelik, register
bir nesne bildirimine başvurmanın , oluşturulan kodun kötüleşme olasılığının daha yüksek olmasıdır , çünkü derleyicinin kendi kayıt tahsisine müdahale eder. Yararlı olduğu birkaç durum olabilir (örneğin, bir değişkene ne sıklıkta erişileceğini gerçekten biliyorsanız ve bilginiz modern bir optimizasyon derleyicisinin anlayabileceğinden daha iyidir).
Başlıca somut etkisi, register
bir nesnenin adresini alma girişimini engellemesidir. Bu, bir optimizasyon ipucu olarak özellikle yararlı değildir, çünkü yalnızca yerel değişkenlere uygulanabilir ve bir optimizasyon derleyicisi böyle bir nesnenin adresinin alınmadığını kendisi görebilir.
register
bu ne sen düşünme eğer ulaşım kolaylığı dizi nesnesi.
register
Dizi nesneleri tanımlamakta yanılmışım ; cevabımda güncellenen ilk madde işaretine bakın. Böyle bir nesneyi tanımlamak yasaldır, ancak onunla hiçbir şey yapamazsınız. Eğer eklerseniz register
tanımına s
yer senin Örneğin , program aynı kısıtlama yoktur C. C ++ (a kısıtlama ihlali) yasadışı register
programı geçerli C olurdu böylece ++, (ancak kullanarak register
anlamsız olurdu).
register
Anahtar kelime, böyle bir değişkenin adresini almak yasal olsaydı yararlı bir amaca hizmet edebilirdi, ancak yalnızca semantiğin, adresi alındığında bir geçici dosyaya kopyalayarak ve geçici dosyadan yeniden yükleyerek etkilenmeyeceği durumlarda sonraki sıra noktasında. Bu, derleyicilerin, adresinin alındığı herhangi bir yerde yıkanması şartıyla, değişkenin tüm işaretçi erişimlerinde güvenli bir şekilde bir kayıtta tutulabileceğini varsaymasına izin verecektir.
Hikaye zamanı!
C, dil olarak bir bilgisayarın soyutlamasıdır. Bir bilgisayarın ne yaptığı, hafızayı manipüle eden, matematik, şeyleri basan vb.
Ancak C sadece bir soyutlamadır. Ve nihayetinde, senden elde ettiği şey Meclis dilidir. Montaj CPU'nun okuduğu dildir ve kullanırsanız CPU açısından bir şeyler yaparsınız. CPU ne yapar? Temel olarak, bellekten okur, matematik yapar ve belleğe yazar. CPU sadece bellekteki sayılar üzerinde matematik yapmakla kalmaz. İlk olarak, CPU içinde a adlı bir sayıyı bellekten belleğe taşımalısınız kayıt. Bu numaraya ne yapmanız gerekiyorsa işinizi bitirdikten sonra, normal sistem belleğine geri taşıyabilirsiniz. Neden sistem belleğini kullanıyorsunuz? Kayıtların sayısı sınırlıdır. Modern işlemcilerde sadece yüz bayt alırsınız ve eski popüler işlemciler daha da fevkalade sınırlıydı (6502'nin ücretsiz kullanımınız için 3 8 bit kaydı vardı). Yani, ortalama matematik işleminiz şöyle görünür:
load first number from memory
load second number from memory
add the two
store answer into memory
Bunların çoğu matematik değil. Bu yükleme ve depolama işlemleri, işlem sürenizin yarısına kadar sürebilir. C, bilgisayarların bir soyutlaması olarak, programcıların kayıtların kullanımı ve hokkabazlığı endişesini serbest bıraktı ve sayı ve tür bilgisayarlar arasında değiştiği için C, kayıt tahsisi sorumluluğunu sadece derleyiciye yerleştirir. Bir istisna dışında.
Bir değişken bildirdiğinizde register
derleyicisine "Yo, bu değişkenin çok kullanılmasını ve / veya kısa ömürlü olmasını istiyorum. Sen olsaydım, bunu bir kayıtta tutmaya çalışırdım." C standardı derleyicilerin aslında hiçbir şey yapması gerekmediğini söylediğinde, bunun nedeni C standardı için hangi bilgisayarı derlediğinizi bilmiyor ve yukarıdaki 6502 gibi olabilir. ve numaranızı saklayacak yedek kayıt yok. Ancak, adresi alamayacağınızı söylediğinde, bunun nedeni, kayıtların adreslerinin olmamasıdır. Onlar işlemcinin elleri. Derleyici size bir adres vermek zorunda olmadığından ve hiçbir zaman bir adrese sahip olamadığından, derleyiciye birkaç optimizasyon açıktır. Örneğin, numarayı her zaman bir kayıt defterinde tutabilir. Öyle değil t Bilgisayar belleğinde nerede depolandığı konusunda endişelenmeniz gerekir (tekrar geri almanın ötesinde). Hatta başka bir değişkene çevirebilir, başka bir işlemciye verebilir, değişen bir konum verebilir, vb.
tl; dr: Çok fazla matematik yapan kısa ömürlü değişkenler. Aynı anda çok fazla beyan etmeyin.
Derleyicinin gelişmiş grafik renklendirme algoritmasıyla uğraşıyorsunuz. Bu, kayıt tahsisi için kullanılır. Pekala, çoğunlukla. Derleyiciye bir ipucu görevi görür - bu doğru. Ancak bir kayıt değişkeninin adresini alma izniniz olmadığından tamamen göz ardı edilmez (derleyicinin, şimdi merhametinize göre, farklı davranmaya çalışacağını unutmayın). Hangi bir şekilde onu kullanmamanızı söylüyor.
Anahtar kelime uzun, uzun geri kullanıldı. İşaret parmağınızı kullanarak hepsini sayabilecek kadar az kayıt olduğunda.
Ancak, dediğim gibi, kullanımdan kaldırılmış olması onu kullanamayacağınız anlamına gelmez.
Sadece karşılaştırma için (herhangi bir gerçek dünya amaç olmadan) biraz demo: çıkartırken register
her değişken önce anahtar kelimeleri, bu kod parçası, benim i7 (GCC) üzerinde 3.41 saniye sürer ile register
0.7 saniyede aynı kod tamamlanıncaya.
#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;
}
Aşağıdaki kodu kullanarak kayıt anahtar kelimesini QNX 6.5.0 altında test ettim:
#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;
}
Aşağıdaki sonuçları aldım:
-> 807679611 döngü geçti
-> Bu sistem saniyede 3300830000 devire sahiptir
-> Saniye cinsinden döngü sayısı ~ 0.244600
Ve şimdi int olmadan kayıt:
int a=0, b = 1, c = 3, i;
Bende var:
-> 1421694077 döngü geçti
-> Bu sistem saniyede 3300830000 devire sahiptir
-> Saniye cinsinden döngü sayısı ~ 0.430700
Kayıt, derleyiciye kodlayıcının bu değişkenin, değişken kullanım için mevcut olan birkaç kayıttan birinde depolanmasını haklı çıkaracak kadar yazıldığını / okunacağını düşündüğünü bildirir. Kayıtlardan okuma / yazma genellikle daha hızlıdır ve daha küçük bir op kodu seti gerektirebilir.
Günümüzde bu, pek çok derleyicinin optimize edicisi, bu değişken için bir kayıt kullanılıp kullanılmayacağını ve ne kadar süreyle kullanılacağını belirlemede sizden daha iyi olduğu için çok yararlı değildir.
Yetmişli yıllarda, C dilinin en başında, programcının derleyiciye ipuçları vermesine izin vermek için değişkenin çok sık kullanılacağını ve bunun akıllıca olması gerektiğini bildirmek için register anahtar sözcüğü eklenmiştir. değerini işlemcinin dahili kaydından birinde tutun.
Günümüzde, optimize ediciler, kayıtlarda tutulması daha olası değişkenleri belirlemek için programcılardan çok daha verimlidir ve optimizer her zaman programlayıcının ipucunu dikkate almaz.
Pek çok kişi yanlışlıkla register anahtar kelimesini kullanmamanızı tavsiye ediyor.
Bakalım neden!
Register anahtar kelimesinin ilişkili bir yan etkisi vardır: bir kayıt türü değişkenine başvuramazsınız (adresini alamazsınız).
Başkalarına kayıt kullanmamalarını tavsiye eden insanlar bunu yanlış bir ek argüman olarak görürler.
Bununla birlikte, bir kayıt değişkeninin adresini alamayacağınızı bilmenin basit gerçeği, derleyicinin (ve optimize edicisinin) bu değişkenin değerinin bir işaretçi aracılığıyla dolaylı olarak değiştirilemeyeceğini bilmesini sağlar.
Komut akışının belirli bir noktasında, bir kayıt değişkeni değerinin bir işlemci kaydına atanmışsa ve kayıt başka bir değişkenin değerini almak için kullanılmadığında, derleyici yeniden yüklemeye gerek olmadığını bilir bu kayıttaki değişkenin değeri. Bu pahalı gereksiz bellek erişiminden kaçınmaya izin verir.
Kendi testlerinizi yapın ve en iç döngülerinizde önemli performans geliştirmeleri elde edeceksiniz.
Kayıt anahtar kelimesi derleyiciye belirli bir değişkeni hızlı bir şekilde erişilebilir olması için CPU kayıtlarında saklamasını söyler. Bir programcının bakış açısından register anahtar sözcüğü, bir programda yoğun olarak kullanılan değişkenler için kullanılır, böylece derleyici kodu hızlandırabilir. Derleyiciye değişkenin CPU kayıtlarında mı yoksa ana bellekte mi tutulacağına bağlı olmasına rağmen.
Kayıt, derleyiciye söz konusu değişkeni kayıtlarda ve sonra bellekte depolayarak bu kodu optimize etmek için kullanılır. derleyici için bir taleptir, derleyici bu talebi değerlendirebilir veya etmeyebilir. Değişkenlerinizin bir kısmına çok sık erişilmesi durumunda bu özelliği kullanabilirsiniz. Örn: Bir döngü.
Bir şey daha, bir değişkeni kayıt olarak bildirirseniz, belleğe kaydedilmediğinden adresini alamazsınız. CPU kaydında tahsisini alır.
gcc 9.3 asm çıkışı, optimizasyon bayrakları kullanmadan (bu yanıttaki her şey optimizasyon bayrakları olmadan standart derleme anlamına gelir):
#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
Bu ebx
hesaplama için kullanılacak güçler , yani yığına itilmesi ve fonksiyonun sonunda geri yüklenmesi gerektiği için geri yüklenmesi gerekir. register
daha fazla kod satırı ve 1 bellek yazma ve 1 bellek okuma üretir (gerçekçi olmasına rağmen, hesaplama yapıldıysa bu 0 R / W'ye optimize edilebilirdi esi
, C ++ 'ları kullanarak olan şey budur const register
). Kullanılmaması register
2 yazma ve 1 okumaya neden olur (her ne kadar yük iletme deposu okumada gerçekleşir). Bunun nedeni, değerin doğrudan yığın üzerinde bulunması ve güncellenmesi gerektiğidir, böylece doğru değer adresle (işaretçi) okunabilir. register
bu gereksinimi yoktur ve gösterilemez. const
ve register
temelde karşıt olan volatile
ve kullananvolatile
dosya ve blok kapsamındaki sabit optimizasyonları ve blok kapsamındaki optimizasyonları geçersiz kılar register
. const register
ve register
aynı çıktılar üretecektir çünkü const blok-kapsamındaki C üzerinde hiçbir şey yapmaz, bu nedenle sadece register
optimizasyonlar geçerlidir.
Clang'da register
göz ardı edilir, ancak const
optimizasyonlar hala gerçekleşir.