Register anahtar kelimesi aslında ne zaman C?


11

registerC'de anahtar kelime kullanımı konusunda kafam karıştı . Genellikle, stackoverflow ile ilgili bu sorudaki gibi kullanımının gerekli olmadığı söylenir .

Bu anahtar kelime, modern derleyiciler nedeniyle C'de tamamen gereksiz mi veya hala yararlı olabileceği durumlar var mı? Evetse, registeranahtar kelime kullanımının gerçekten yararlı olduğu bazı durumlar nelerdir?


4
Bence bağlantılı soru ve cevapları burada beklediğiniz gibi aynı. Yani buraya ulaşabileceğiniz yeni bir bilgi olmayacak.
Uwe Plonus

@UwePlonus constAnahtar kelime için aynı şeyi düşündüm ama bu soru benim yanlış olduğumu kanıtladı. Bu yüzden bekleyeceğim ve ne aldığımı göreceğim.
Aseem Bansal

Ben constanahtar kelime kayıt karşı farklı bir şey olduğunu düşünüyorum .
Uwe Plonus

4
Yanlışlıkla zamanda geriye giderseniz ve erken C derleyicilerinden birini kullanmak zorunda kalırsanız kullanışlıdır. Bunun dışında hiç faydalı değil, yıllardır tamamen modası geçmiş.
JohnB

@UwePlonus Sadece bir anahtar kelimenin yararlı olabileceği bilinmeyen senaryolar olabileceğini söyledim.
Aseem Bansal

Yanıtlar:


12

Dil açısından gereksiz değildir, sadece bunu kullanarak derleyiciye, bir değişkenin kayıt defterinde depolanmasını "tercih edeceğinizi" söylersiniz. Bununla birlikte, bunun çalışma zamanında gerçekleşeceğinin kesinlikle sıfır garantisi vardır.


9
Dahası, derleyicinin en iyi bildiği hemen hemen her zaman böyledir ve nefesinizi boşa harcıyorsunuz
Daniel Gratzer

6
@ jozefg: daha da kötüsü. Derleyicinin isteğinizi / ipucunuzu onurlandırması ve sonuç olarak daha kötü kod üretmesi riskini taşırsınız .
Bart van Ingen Schenau

10

Daha önce de belirtildiği gibi, derleyici optimize edicileri registeranahtar kelimeyi temel olarak takma adı engellemekten başka amaçlar için kullanılmaz hale getirir . Ancak optimizasyonu (kapalı derlenen tüm codebases vardır -O0içinde gcc-speak ). Böyle bir kod için, registeranahtar kelimenin büyük etkisi olabilir. Özellikle, aksi yığını bir yuva olması alacağı değişkenler (tüm işlev parametreleri ve otomatik değişkenler yani) olabilir ile beyan eğer bir kayıt doğrudan yerleştirilebilir registeranahtar kelime.

İşte gerçek dünyadan bir örnek: bazı veritabanı alımının gerçekleştiğini ve alım kodunun alınan tuplei bir C yapısına doldurduğunu varsayın. Ayrıca, bu C yapısının bazı alt kümelerinin başka bir yapıya kopyalanması gerektiğini varsayalım; belki bu ikinci yapı, veritabanında depolanan meta verileri temsil eden, bellek kısıtlamaları nedeniyle her meta veri kaydının yalnızca bir alt kümesini depolandığı gibi önbelleğe alan veritabanında.

Her yapı türüne bir işaretçi alan ve tek görevi başlangıçtaki yapıdan ikinci yapıya bazı üyeleri kopyalamak olan bir işlev verildiğinde: yapı işaretçisi değişkenleri yığın üzerinde yaşayacaktır. Bir yapının üyelerinden diğerine atamalar gerçekleştikçe, her atama için yapının adresleri, kopyalanan yapı üyelerinin erişimini gerçekleştirmek için bir kayıt defterine yüklenir. Yapı işaretçileri registeranahtar sözcükle bildirilecek olsaydı, yapıların adresleri kayıtlarda kalır ve her atama için yük-adres-kayıt talimatlarını etkili bir şekilde keserdi.

Yine, yukarıdaki açıklamanın optimize edilmemiş kod için geçerli olduğunu unutmayın .


7

Temel olarak derleyiciye değişkenin adresini almayacağınızı söylersiniz ve derleyici görünüşte daha fazla optimizasyon yapabilir. Bildiğim kadarıyla, modern derleyiciler bir değişkenin bir kayıt defterinde tutulup tutulmayacağını belirleyebilmektedir.

Misal:

int main(){
        int* ptr;
        int a;
        register int b;
        ptr = &a;
        ptr = &b; //this won't compile
        return 0;
} 

Dereference veya adresini al?
detly

@detly: elbette haklısın
Lucas

1

16-bit bilgisayar günlerinde, 32-bit çarpma ve bölme işlemlerini yürütmek için genellikle birden fazla kayıt gerekir. Kayan nokta birimleri yongalara dahil edildiğinde ve daha sonra 64-bit mimariler 'devraldı' olarak, hem kayıtların genişliği hem de sayısı arttı. Bu, nihayetinde CPU'nun tamamen yeniden yapılandırılmasına yol açar. Bkz . Wikipedia'da Dosya Kaydetme .

Kısacası, 64 bit X86 veya ARM çipindeyseniz gerçekte neler olup bittiğini anlamanız biraz zaman alacaktır. 16 bitlik gömülü bir CPU kullanıyorsanız, bu aslında size bir şey kazandırabilir. Bununla birlikte, küçük gömülü yongaların çoğu zaman açısından kritik bir şey yapmaz - mikrodalga fırınınız saniyede 10.000 kez dokunmatik yüzeyinizi örnekliyor olabilir - 4Mhz CPU'yu zorlayan hiçbir şey.


1
4 MIPS / 10.000 anket / sn = 400 talimat / anket. Bu neredeyse istediğiniz kadar marj değil. Ayrıca oldukça az sayıda 4 MHz işlemcinin dahili olarak mikro kodlandığını, yani 1 MIP / MHz yakınında hiçbir yerde olmadıklarını unutmayın.
John R. Strohm

@ JohnR.Strohm - Kaç tane talimat döngüsü alacağını tam olarak anlayabileceğiniz durumlar olabilir, ancak şimdi daha ucuz bir yol daha hızlı bir çip almak ve ürünü kapıdan çıkarmaktır. Verilen örnekte, elbette, eğer bir komutu varsa, 10.000'de örneklemeye devam etmek zorunda değildir - zarar vermeden saniyenin çeyreği boyunca örneklemeye devam etmeyebilir. Programcıya yönelik optimizasyonun nerede önemli olduğunu anlamak gittikçe zorlaşıyor.
Meredith Poor

1
"Sadece daha hızlı bir yonga almak ve ürünü kapıdan çıkarmak" her zaman mümkün değildir. Gerçek zamanlı görüntü işlemeyi düşünün. 640x480 piksel / kare x 60 kare / saniye x N piksel başına talimat hızlı bir şekilde eklenir. (Gerçek zamanlı görüntü işlemeden alınan ders, piksel çekirdekleriniz üzerinde kan terlemeniz ve hemen hemen her şeyi görmezden gelmenizdir, çünkü satır başına yüzlerce kez değil, satır başına bir kez veya yama başına bir kez veya kare başına bir kez veya yama veya çerçeve başına onlarca veya yüz binlerce kez.)
John R. Strohm

@ JohnR.Strohm - gerçek zamanlı görüntü işleme örneğini alarak, minimum ortamın 32 bit olduğunu varsayarım. Bir uzuvda çıkmak (bunun ne kadar pratik olduğunu bilmediğim için) yongalara yerleştirilmiş birçok grafik hızlandırıcı da görüntü tanıma için kullanılabilir, bu nedenle entegre oluşturma motorlarına sahip ARM yongalarının (örneğin) ek ALU'ları kullanılabilir tanıma için. O zamana kadar optimizasyon için 'register' anahtar kelimesinin kullanılması sorunun küçük bir kısmıdır.
Meredith Poor

-3

Register anahtar kelimesinin herhangi bir anlamı olup olmadığını belirlemek için, küçük örnek kodlar işe yaramaz. İşte bana öneren bir c-kodu, register anahtar kelimesinin hala bir önemi var. Ama Linux'taki GCC ile farklı olabilir, bilmiyorum. İnt k & l bir CPU kaydında saklanıp saklanmayacak mı? Linux kullanıcıları (özellikle) GCC ve optimizasyon ile derlemelidir. Borland bcc32 ile, & -operator, kayıt olarak bildirilen tamsayılar için hata kodları verdiğinden, kayıt anahtar kelimesi işlev görür (bu örnekte). NOT! Windows'ta Borland ile küçük bir örnekte durum böyle değil! Derleyicinin neyi optimize edip etmediğini gerçekten görmek için küçük bir örnek olmaktan daha fazlası olmalıdır. Boş döngüler olmaz! Bununla birlikte - Bir adres & -operator ile okunamıyorsa, değişken bir CPU kaydında saklanmaz. Ancak, bir kayıt bildirilen değişken okunamıyorsa (derleme sırasında hata koduna neden oluyorsa) - register anahtar sözcüğünün aslında değişkeni bir CPU kaydına koyduğunu varsaymalıyım. Farklı platformlarda farklı olabilir, bilmiyorum. (Çalışırsa, "keneler" sayısı kayıt bildirimiyle çok daha düşük olacaktır.

/* reg_or_not.c */  

#include <stdio.h>
#include <time.h>
#include <stdlib> //not requiered for Linux
#define LAPSb 50
#define LAPS 50000
#define MAXb 50
#define MAX 50000


int main (void)
{
/* 20 ints and 2 register ints */   

register int k,l;
int a,aa,b,bb,c,cc,d,dd,e,ee,f,ff,g,gg,h,hh,i,ii,j,jj;


/* measure some ticks also */  

clock_t start_1,start_2; 
clock_t finish_1,finish_2;
long tmp; //just for the workload 


/* pointer declarations of all ints */

int *ap, *aap, *bp, *bbp, *cp, *ccp, *dp, *ddp, *ep, *eep;
int *fp, *ffp, *gp, *ggp, *hp, *hhp, *ip, *iip, *jp, *jjp;
int *kp,*lp;

/* end of declarations */
/* read memory addresses, if possible - which can't be done in a CPU-register */     

ap=&a; aap=&aa; bp=&b; bbp=&bb;
cp=&c; ccp=&cc; dp=&d; ddp=&dd;
ep=&e; eep=&ee; fp=&f; ffp=&ff;
gp=&g; ggp=&gg; hp=&h; hhp=&hh;
ip=&i; iip=&ii; jp=&j; jjp=&jj;

//kp=&k;  //won't compile if k is stored in a CPU register  
//lp=&l;  //same - but try both ways !


/* what address , isn't the issue in this case - but if stored in memory    some "crazy" number will be shown, whilst CPU-registers can't be read */

printf("Address a aa: %u     %u\n",a,aa);
printf("Address b bb: %u     %u\n",b,bb);
printf("Address c cc: %u     %u\n",c,cc);
printf("Address d dd: %u     %u\n",d,dd);
printf("Address e ee: %u     %u\n",e,ee);
printf("Address f ff: %u     %u\n",f,ff);
printf("Address g gg: %u     %u\n",g,gg);
printf("Address h hh: %u     %u\n",h,hh);
printf("Address i ii: %u     %u\n",i,ii);
printf("Address j jj: %u     %u\n\n",j,jj);

//printf("Address k:  %u \n",k); //no reason to try "k" actually is in a CPU-register 
//printf("Address l:  %u \n",l); 


start_2=clock(); //just for fun      

/* to ensure workload */
for (a=1;a<LAPSb;a++) {for (aa=0;aa<MAXb;aa++);{tmp+=aa/a;}}
for (b=1;b<LAPSb;b++) {for (bb=0;bb<MAXb;bb++);{tmp+=aa/a;}}
for (a=1;c<LAPSb;c++) {for (cc=0;cc<MAXb;cc++);{tmp+=bb/b;}}
for (d=1;d<LAPSb;d++) {for (dd=0;dd<MAXb;dd++);{tmp+=cc/c;}}
for (e=1;e<LAPSb;e++) {for (ee=0;ee<MAXb;ee++);{tmp+=dd/d;}}
for (f=1;f<LAPSb;f++) {for (ff=0;ff<MAXb;ff++);{tmp+=ee/e;}}
for (g=1;g<LAPSb;g++) {for (gg=0;gg<MAXb;gg++);{tmp+=ff/f;}}
for (h=1;h<LAPSb;h++) {for (hh=0;hh<MAXb;hh++);{tmp+=hh/h;}}
for (jj=1;jj<LAPSb;jj++) {for (ii=0;ii<MAXb;ii++);{tmp+=ii/jj;}}

start_1=clock(); //see following printf
for (i=0;i<LAPS;i++) {for (j=0;j<MAX;j++);{tmp+=j/i;}} /* same double   loop - in supposed memory */
finish_1=clock(); //see following printf

printf ("Memory: %ld ticks\n\n", finish_1 - start_1); //ticks for memory

start_1=clock(); //see following printf
for (k=0;k<LAPS;k++) {for (l=0;l<MAX;l++);{tmp+=l/k;}}  /* same double       loop - in supposed register*/
finish_1=clock(); //see following printf     

printf ("Register: %ld ticks\n\n", finish_1 - start_1); //ticks for CPU register (?) any difference ?   

finish_2=clock();

printf ("Total: %ld ticks\n\n", finish_2 - start_2); //really for fun only           

system("PAUSE"); //only requiered for Windows, so the CMD-window doesn't vanish     

return 0;

} 

Yukarıda sıfır olan bir bölüm olacak, lütfen {tmp + = ii / jj;} değerini {tmp + = jj / ii;} olarak değiştirin - bunun için gerçekten üzgünüm
John P Eriksson

Ayrıca k ve i 1 ile başlasın - sıfır değil. Çok üzgünüm.
John P Eriksson

3
Yorumlarda düzeltme yazmak yerine cevabınızı düzenleyebilirsiniz.
Jan Doggen
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.