Jsem zmatený ohledně použití klíčového slova register
v jazyce C. Obecně se říká, že jeho použití není “ není potřeba jako v této otázce na StackOverflow .
Je toto klíčové slovo v C díky moderním překladačům naprosto nadbytečné nebo existují situace, ve kterých je může být stále užitečné? Pokud ano, v jakých situacích je použití klíčového slova register
skutečně užitečné?
Komentáře
- Myslím, že propojená otázka a odpovědi na ni jsou stejné, jaké zde můžete očekávat. Takže zde nebudete mít žádné nové informace.
- @UwePlonus totéž o
const
klíčovém slovu, ale tato otázka prokázala, že se mýlím. Takže jsem ‚ Počkám a uvidím, co dostanu. - Myslím, že klíčové slovo
const
je něco jiného než registr. - It ‚ je užitečné, pokud se náhodou vrátíte zpět v čase a jste nuceni použít některý z prvních překladačů C. Kromě toho to ‚ není vůbec užitečné, ‚ to bylo po celá léta zcela zastaralé.
- @ UwePlonus Chtěl jsem jen říct, že mohou existovat neznámé scénáře, ve kterých by klíčové slovo mohlo být užitečné.
Odpověď
Není to z hlediska jazyka nadbytečné, je to jen to, že jeho používáním říkáte kompilátoru, že byste „raději“ uložili proměnnou v registru. Existuje však absolutně nulová záruka, že to skutečně bude během běhu.
Komentáře
- Více než to, ‚ téměř vždy platí, že překladač to ví nejlépe a vy ‚ plýtváte dechem
- @jozefg: ještě horší. Riskujete, že překladač splní váš požadavek / nápovědu a vytvoří
horší kód.
Odpověď
Jak již bylo zmíněno, optimalizátory kompilátoru v podstatě ren der register
klíčové slovo zastaralé pro jiné účely než pro zabránění aliasingu. Existují však celé databáze kódů, které jsou kompilovány s vypnutou optimalizací (-O0
v gcc-speak ). Pro takový kód může mít klíčové slovo register
velký účinek. Konkrétně proměnné, které by jinak získaly slot v zásobníku (tj. Všechny funkční parametry a automatické proměnné) mohou být umístěny přímo do registru, pokud jsou deklarovány pomocí register
klíčové slovo.
Zde je příklad z reálného světa: Předpokládejme, že došlo k nějakému načtení databáze a že kód pro načtení vložil získanou n-tici do struktury C. Dále předpokládejme, že některá podmnožina této struktury C je třeba zkopírovat do jiné struktury – možná tato druhá struktura je záznam mezipaměti, který představuje metadata uložená v databázi, která z důvodu omezení paměti ukládá do mezipaměti pouze podmnožinu každého záznamu metadat uloženého v databázi.
Vzhledem k funkci, která vezme ukazatel na každý typ struktury a jehož jediným úkolem je kopírovat některé členy z počáteční struktury do druhé struktury: proměnné ukazatele struktury budou žít v zásobníku. Protože přiřazení se vyskytují od členů struktury ostatním adresám budou adresy struktur pro každé přiřazení být načten do registru za účelem provedení přístupu členů struktury, které jsou kopírovány. Pokud by měly být ukazatele struktury deklarovány pomocí klíčového slova register
, adresy struktur by zůstaly v registrech, což by účinně vyřízlo pokyny pro načtení adresy do registru pro každé přiřazení.
Nezapomeňte, že výše uvedený popis platí pro neoptimalizovaný kód.
Odpověď
V zásadě řeknete kompilátoru, že adresu proměnné nepřijmete a kompilátor pak může zdánlivě vytvořit další optimalizace. Pokud vím, moderní překladače dokážou docela dobře určit, zda proměnná může / má být uchovávána v registru nebo ne.
Příklad:
int main(){ int* ptr; int a; register int b; ptr = &a; ptr = &b; //this won"t compile return 0; }
Komentáře
- Dereference nebo převzetí adresy?
- @detly: máte samozřejmě pravdu
Odpověď
V 16bitových počítačových dnech jeden často potřeboval více registrů k provádění 32bitových násobení a dělení. jednotky s plovoucí desetinnou čárkou byly začleněny do čipů a poté „převzaly“ 64bitové architektury, a to jak šířku registrů, tak jejich počet rozšířen. To nakonec vede k úplné re-architektuře CPU. Viz Registrovat soubory na Wikipedii.
Stručně řečeno, zabrat vám trochu času by trvalo Zjistěte, co se ve skutečnosti děje, pokud používáte 64bitový čip X86 nebo ARM.Pokud používáte 16bitový vestavěný procesor, mohlo by vám to něco přinést. Většina malých vestavěných čipů však nespustí nic časově kritického – vaše mikrovlnná trouba může vzorkovat váš touchpad 10 000krát za sekundu – nic, co by 4MHz CPU.
Komentáře
- 4 MIPS / 10 000 dotazů / s = 400 pokynů / dotazování. To ‚ není ani zdaleka tolik marže, kolik byste ‚ chtěli mít. Všimněte si také, že několik procesorů o frekvenci 4 MHz bylo interně mikrokódováno, což znamená, že se ani zdaleka nepřibližovaly k 1 MIP / MHz.
- @ JohnR.Strohm – Mohly by nastat situace, kdy by bylo možné ospravedlnit přesné zjištění počtu instrukcí cykluje to ‚ to bude trvat, ale často je nyní levnější cestou získat rychlejší čip a dostat produkt ze dveří. V uvedeném příkladu samozřejmě člověk nemusí ‚ pokračovat ve vzorkování na 10 000, pokud má příkaz – nemusí pokračovat ve vzorkování na čtvrt sekundy bez poškození Hotovo. Je stále obtížnější zjistit, kde bude záležet na optimalizaci řízené programátorem.
- Není vždy možné “ získat rychlejší čip a získat produkt venku „. Zvažte zpracování obrazu v reálném čase. 640 x 480 pixelů / snímek x 60 snímků / s x N instrukce na pixel se přidává rychle. (Lekce ze zpracování obrazu v reálném čase spočívá v tom, že potíte krev nad pixelovými jádry a téměř všechno ignorujete, protože běží jednou na řádek nebo jednou na opravu nebo jednou na snímek, na rozdíl od stovekkrát na řádek nebo patch nebo desítky či stovky tisíckrát na snímek.)
- @ JohnR.Strohm – při příkladu zpracování obrazu v reálném čase bych předpokládal, že minimální prostředí je 32 bitů. Jít ven na končetinu (protože ‚ nevím, jak je to praktické) mnoho grafických akcelerátorů zabudovaných do čipů může být také použitelné pro rozpoznávání obrázků, takže čipy ARM (například ), které mají integrované vykreslovací motory, mohou mít další ALU použitelné pro rozpoznání. Do té doby je použití klíčového slova ‚ ‚ pro optimalizaci malou částí problému.
Odpověď
Chcete-li zjistit, zda klíčové slovo registru má nějaký význam, nebudou malé ukázkové kódy provedeny. Zde je c-kód což mi naznačuje, že klíčové slovo registru má stále význam. Ale u GCC v Linuxu to může být jiné, nevím. BUDETE registr int k & uložen v registru CPU nebo ne? Uživatelé systému Linux (zejména) by měli kompilovat s GCC a optimalizací. U Borland bcc32 se zdá, že klíčové slovo registru funguje (v tomto příkladu), protože & -operator dává chybové kódy pro registr deklarovaná celá čísla. POZNÁMKA! To NENÍ případ malého příkladu Borlandu ve Windows! Aby bylo možné skutečně zjistit, co kompilátor optimalizuje nebo ne, musí to být jen nepatrný příklad. Prázdné smyčky nebudou provedeny! Nicméně – POKUD Lze číst adresu pomocí operátoru &, proměnná není uložena v registru CPU. Pokud ale proměnnou deklarovanou v registru nelze přečíst (což způsobí chybový kód při kompilaci) – musím předpokládat, že klíčové slovo registru ve skutečnosti tuto proměnnou vloží do registru CPU. Na různých platformách se může lišit, nevím . (Pokud to funguje, počet „klíšťat“ bude s deklarací registru mnohem nižší.
/* 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=ⅆ ep=&e; eep=ⅇ fp=&f; ffp=&ff; gp=&g; ggp=≫ hp=&h; hhp=&hh; ip=&i; iip=ⅈ 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; }
Komentáře
- Nahoře bude divize s nulou, změňte prosím {tmp + = ii / jj;} na {tmp + = jj / ii;} – za to se opravdu omlouvám
- Nechte také k a i začněte 1 – ne nula. Velmi se omlouvám.
- Odpověď můžete upravit, aniž byste do komentářů museli psát opravy.