Quand le mot-clé register est-il réellement utile en C?

Je ne sais pas comment utiliser le mot-clé register en C. On dit généralement que son utilisation nest  » t nécessaire comme dans cette question sur stackoverflow .

Ce mot-clé est-il totalement redondant en C en raison des compilateurs modernes ou y a-t-il des situations dans lesquelles il peut encore être utile? Si oui, quelles sont les situations dans lesquelles lutilisation du mot clé register est réellement utile?

Commentaires

  • Je pense que la question liée et les réponses à celle-ci sont les mêmes que celles auxquelles vous pouvez vous attendre ici. Il ny aura donc aucune nouvelle information que vous pourrez obtenir ici.
  • @UwePlonus Je pensais que le idem pour le mot clé const mais cette question a prouvé que javais tort. Donc, ‘ Je vais attendre et voir ce que jobtiens.
  • Je pense que le mot-clé const est différent de celui du registre.
  • Il ‘ est utile si vous revenez accidentellement dans le temps et que vous êtes obligé dutiliser lun des premiers compilateurs C. À part cela, ‘ nest pas du tout utile, ‘ est entièrement obsolète depuis des années.
  • @ UwePlonus Je voulais simplement dire quil peut y avoir des scénarios inconnus de moi dans lesquels un mot-clé pourrait être utile.

Réponse

Ce nest pas redondant en termes de langage, cest juste quen lutilisant, vous dites au compilateur que vous « préféreriez » avoir une variable stockée dans le registre. Il ny a cependant absolument aucune garantie que ce sera réellement se produisent pendant lexécution.

Commentaires

  • Plus que cela, ‘ est presque toujours le cas où le compilateur sait le mieux et vous ‘ gaspillez votre souffle
  • @jozefg: encore pire. Vous courez le risque que le compilateur honore votre demande / indice et produise pire code en conséquence.

Réponse

Comme déjà mentionné, les optimiseurs de compilateurs essentiellement ren der le mot-clé register obsolète à des fins autres que la prévention des alias. Cependant, il existe des bases de code entières qui sont compilées avec loptimisation désactivée (-O0 dans gcc-speak ). Pour un tel code, le mot-clé register peut avoir un grand effet. Plus précisément, les variables qui auraient autrement un emplacement sur la pile (cest-à-dire tous les paramètres de fonction et les variables automatiques) peuvent être placées directement dans un registre si elles sont déclarées avec register mot-clé.

Voici « un exemple du monde réel: supposons quune récupération de base de données a eu lieu et que le code de récupération a bourré le tuple récupéré dans une structure C. De plus, supposons quun sous-ensemble de cette structure C doit être copié dans une autre structure – peut-être que cette seconde structure est un enregistrement de cache qui représente les métadonnées stockées dans la base de données qui, en raison de contraintes de mémoire, ne met en cache quun sous-ensemble de chaque enregistrement de métadonnées stocké dans la base de données.

Étant donné une fonction qui prend un pointeur sur chaque type de structure et dont le seul travail est de copier certains membres de la structure initiale vers la deuxième structure: les variables de pointeur de structure vivront sur la pile. Comme les affectations se produisent à partir des membres dune structure aux autres, les adresses de la structure seront, pour chaque affectation, être chargé dans un registre afin deffectuer laccès aux membres de la structure en cours de copie. Si les pointeurs de structure devaient être déclarés avec le mot-clé register, les adresses des structures resteraient dans les registres, supprimant effectivement les instructions de chargement dadresse dans le registre pour chaque affectation.

Encore une fois, rappelez-vous que la description ci-dessus sapplique au code non optimisé .

Réponse

En gros, vous dites au compilateur que vous ne prendrez pas l’adresse de la variable et le compilateur peut alors apparemment faire Pour autant que je sache, les compilateurs modernes sont assez capables de déterminer si une variable peut / doit être conservée dans un registre ou non.

Exemple:

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

Commentaires

  • Déréférencer ou prendre ladresse de?
  • @detly: vous avez bien sûr raison

Réponse

À lépoque des ordinateurs 16 bits, il fallait souvent plusieurs registres pour exécuter des multiplications et des divisions 32 bits. des unités à virgule flottante ont été incorporées dans les puces, puis les architectures 64 bits ont «pris le relais», tant la largeur des registres que le nombre de ceux-ci ont été augmentés. Cela a finalement conduit à une refonte complète du processeur. Voir Enregistrer les fichiers sur Wikipédia.

En bref, il vous faudrait un peu de temps pour trouver Découvrez ce qui se passe réellement si vous utilisez une puce X86 ou ARM 64 bits.Si vous utilisez un processeur intégré 16 bits, cela pourrait vous apporter quelque chose. Cependant, la plupart des petites puces intégrées ne fonctionnent pas à un moment critique – votre four à micro-ondes peut échantillonner votre pavé tactile 10 000 fois par seconde – rien qui ne fatigue un Processeur 4Mhz.

Commentaires

  • 4 MIPS / 10 000 sondages / sec = 400 instructions / sondage. Cette ‘ est loin d’être autant de marge que vous ‘ souhaiteriez avoir. Notez également que bon nombre de processeurs 4 MHz ont été microcodés en interne, ce qui signifie quils étaient loin de 1 MIP / MHz.
  • @ JohnR.Strohm – Il peut y avoir des situations où lon pourrait justifier de déterminer exactement combien dinstructions le cycle ‘ s va prendre, mais souvent la solution la moins chère maintenant est simplement dobtenir une puce plus rapide et de sortir le produit. Dans lexemple donné, bien sûr, on ne ‘ t avoir à continuer à échantillonner à 10 000 si on a une commande – il peut ne pas reprendre léchantillonnage pendant un quart de seconde sans dommage Fini. Il devient de plus en plus difficile de déterminer où l’optimisation dirigée par le programmeur sera importante.
  • Il n’est pas toujours possible de  » simplement obtenir une puce plus rapide et obtenir le produit à la porte « . Pensez au traitement dimage en temps réel. 640×480 pixels / image x 60 images / seconde x N instructions par pixel sajoutent rapidement. (La leçon tirée du traitement dimage en temps réel est que vous transpirez du sang sur vos noyaux de pixels et que vous ignorez à peu près tout le reste, car il sexécute une fois par ligne ou une fois par patch ou une fois par image, par opposition à des centaines de fois par ligne ou patch ou des dizaines ou des centaines de milliers de fois par image.)
  • @ JohnR.Strohm – en prenant lexemple du traitement dimage en temps réel, je suppose que lenvironnement minimum est de 32 bits. Sortir sur une branche (parce que je ne sais ‘ pas à quel point cela est pratique), de nombreux accélérateurs graphiques intégrés aux puces peuvent également être utilisables pour la reconnaissance dimage, donc les puces ARM (par exemple ) qui ont des moteurs de rendu intégrés peuvent avoir des ALU supplémentaires utilisables pour la reconnaissance. À ce moment-là, lutilisation du mot clé ‘ register ‘ pour loptimisation est une infime partie du problème.

Réponse

Afin de déterminer si le mot-clé register a une signification, de minuscules exemples de codes ne sont pas nécessaires. Voici un c-code ce qui me suggère, le mot clé register a toujours une signification. Mais il pourrait être différent avec GCC sous Linux, je ne sais pas. Le registre int k & sera-t-il stocké dans un registre CPU ou non? Les utilisateurs de Linux (en particulier) devraient compiler avec GCC et loptimisation. Avec Borland bcc32, le mot clé register semble fonctionner (dans cet exemple), car lopérateur & donne des codes derreur pour les entiers déclarés par le registre. REMARQUE! Ce nest PAS le cas avec un petit exemple avec Borland sous Windows! Afin de vraiment voir ce que le compilateur optimise ou non, il doit sagir dun plus quun petit exemple. Néanmoins, SI une adresse PEUT être lue avec lopérateur &, la variable nest pas stockée dans un registre CPU. Mais si une variable déclarée de registre ne peut pas être lue (provoquant un code derreur lors de la compilation) – je dois supposer que le mot clé register place effectivement la variable dans un registre CPU. Il peut différer sur diverses plates-formes, je ne sais pas . (Si cela fonctionne, le nombre de « ticks » sera bien inférieur avec la déclaration de registre.

/* 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; } 

Commentaires

  • Il y aura une division avec zéro au-dessus, veuillez changer {tmp + = ii / jj;} en {tmp + = jj / ii;} – vraiment désolé pour cela
  • Laissez également k et i commencer par 1 – pas zéro. Très désolé.
  • Vous pouvez modifier votre réponse au lieu décrire des corrections dans les commentaires.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les champs obligatoires sont indiqués avec *