Kommaoperator

I programmeringsspråken C och C++ är kommaoperatorn (representerad av token , ) en binär operator som utvärderar sin första operand och kasserar resultatet, och sedan utvärderar den andra operanden och returnerar detta värde (och typ); det finns en sekvenspunkt mellan dessa utvärderingar.

Användningen av kommatecken som en operator skiljer sig från dess användning i funktionsanrop och definitioner, variabeldeklarationer, enum-deklarationer och liknande konstruktioner, där den fungerar som en separator .

Kommaoperatorn har fasadt ut i prenumerationsuttryck (från och med C++20 ) ; för att bättre kunna använda den syntaxen, för användning som är tillgänglig på andra språk.

Syntax

Kommaoperatorn separerar uttryck (som har värde) på ett sätt som är analogt med hur semikolon avslutar uttalanden, och sekvenser av uttryck omges av parentes analogt med hur sekvenser av uttalanden är inneslutna av klammerparenteser: (a, b, c) är en sekvens av uttryck, separerade med kommatecken, som evalueras till det sista uttrycket c , medan {a; b; c;} är en sekvens av påståenden och utvärderas inte till något värde. Ett kommatecken kan bara förekomma mellan två uttryck – kommaseparerade uttryck – till skillnad från semikolon, som förekommer i slutet av en (icke-block)-sats – semikolon avslutar uttalanden.

Kommaoperatorn har den lägsta prioritet av någon C-operator och fungerar som en sekvenspunkt . I en kombination av kommatecken och semikolon har semikolon lägre prioritet än kommatecken, eftersom semikolon separerar satser men kommatecken förekommer inom satser, vilket överensstämmer med deras användning som vanlig interpunktion: a, b ; c, d är grupperad som (a, b); (c, d) eftersom detta är två separata påståenden.

Exempel

I det här exemplet beror det olika beteendet mellan den andra och tredje raden på att kommaoperatorn har lägre prioritet än tilldelning. Det sista exemplet skiljer sig också eftersom returuttrycket måste utvärderas helt innan funktionen kan returnera.





    0






                 
               
                      









                                   
      






   
        
          







   
 
       









   
       






   
     







   





   









   /**  * Komtecken fungerar som avgränsare på den här raden, inte som en operator.  * Resultat: a=1, b=2, c=3, i=0  */  int  a  =  1  ,  b  =  2  ,  c  =  3  ,  i  =  ;  /**  * Tilldelar värdet av b till i.  * Komtecken fungerar som avgränsare på den första raden och som en operator på den andra raden.  * Resultat: a=1, b=2, c=3, i=2  */  int  a  =  1  ,  b  =  2  ,  c  =  3  ;  int  i  =  (  a  ,  b  );  /**  * Tilldelar värdet av a till i.  * Motsvarar: int i = a; int b;   * Komtecken fungerar som avgränsare på båda raderna.  * Klammerparenteserna på den andra raden undviker omdeklaration av variabel i samma block, *  vilket skulle orsaka ett kompileringsfel.  * Det andra b som deklareras ges inget initialvärde.  * Resultat: a=1, b=2, c=3, i=1  */  int  a  =  1  ,  b  =  2  ,  c  =  3  ;  {  int  i  =  a  ,  b  ;  }  /**  * Ökar värdet på a med 2 och tilldelar sedan värdet av den resulterande operationen a + b till i.  * Komtecken fungerar som avgränsare på den första raden och som en operator på den andra raden.  * Resultat: a=3, b=2, c=3, i=5  */  int  a  =  1  ,  b  =  2  ,  c  =  3  ;  int  i  =  (  a  +=  2  ,  a  +  b  );  /**  * Ökar värdet på a med 2, lagrar sedan värdet på a till i, och kasserar oanvända  * värden för den resulterande operationen a + b.  * Ekvivalent med: (i = (a += 2)), a + b;  * Komtecken fungerar som avgränsare på den första raden och som en operator på den tredje raden.  * Resultat: a=3, b=2, c=3, i=3  */  int  a  =  1  ,  b  =  2  ,  c  =  3  ;  int  i  ;  i  =  a  +=  2  ,  a  +  b  ;  /**  * Tilldelar värdet av a till i.  * Komtecken fungerar som avgränsare på båda raderna.  * Klammerparenteserna på den andra raden undviker omdeklaration av variabel i samma block, *  vilket skulle orsaka ett kompileringsfel.  * De andra b och c deklarerade ges inget initialvärde.  * Resultat: a=1, b=2, c=3, i=1  */  int  a  =  1  ,  b  =  2  ,  c  =  3  ;  {  int  i  =  a  ,  b  ,  c  ;  }  /**  * Komtecken fungerar som avgränsare på den första raden och som en operator på den andra raden.  * Tilldelar värdet av c till i, och kasserar de oanvända a- och b-värdena.  * Resultat: a=1, b=2, c=3, i=3  */  int  a  =  1  ,  b  =  2  ,  c  =  3  ;  int  i  =  (  a  ,  b  ,  c  );  /**  * Returnerar 6, inte 4, eftersom kommaoperatorsekvenspunkter efter nyckelordet  * return anses vara ett enda uttryck som utvärderas till rvalue av final  * subexpression c=6.  * Komtecken fungerar som operatorer på den här raden.  */  returnera  a  =  4  ,  b  =  5  ,  c  =  6  ;  /**  * Returnerar 3, inte 1, av samma anledning som tidigare exempel.  * Komtecken fungerar som operatorer på den här raden.  */  returnera  1  ,  2  ,  3  ;  /**  * Returnerar 3, inte 1, fortfarande av samma anledning som ovan. Det här exemplet fungerar som det gör   * eftersom return är ett nyckelord, inte ett funktionsanrop. Även om kompilatorer   * tillåter konstruktionen return(value), är parenteserna endast relativa till "value" *  och har ingen speciell effekt på returnyckelordet.  * Return får helt enkelt ett uttryck och här är uttrycket "(1), 2, 3".  * Komtecken fungerar som operatorer på den här raden.  */  return  (  1  ),  2  ,  3  ; 

Används

Kommaoperatorn har relativt begränsade användningsfall. Eftersom den kasserar sin första operand är den i allmänhet endast användbar där den första operanden har önskvärda biverkningar som måste sekvenseras före den andra operanden. Dessutom, eftersom det sällan används utanför specifika idiom, och lätt förväxlas med andra kommatecken eller semikolon, är det potentiellt förvirrande och felbenäget. Icke desto mindre finns det vissa omständigheter där det är vanligt förekommande, särskilt i for loops och i SFINAE . För inbäddade system som kan ha begränsade felsökningsmöjligheter kan kommaoperatorn användas i kombination med ett makro för att sömlöst åsidosätta ett funktionsanrop, för att infoga kod precis före funktionsanropet.

För slingor

Den vanligaste användningen är att tillåta flera tilldelningssatser utan att använda en blocksats, främst i initialiseringen och inkrementeringsuttrycken för en for-loop . Detta är den enda idiomatiska användningen i elementär C-programmering. I följande exempel är ordningen på slingans initierare signifikant:

    

     
               
        
    
 void  rev  (  char  *  s  ,  size_t  len  ​​)  {  char  *  first  ;  for  (  först  =  s  ,  s  +=  len  ;  s  >=  först  ;  --  s  )  {  putchar  (  *  s  );  }  } 

En alternativ lösning på detta problem på andra språk är parallell tilldelning , som gör att flera tilldelningar kan förekomma inom en enda sats, och även använder kommatecken, dock med olika syntax och semantik. Detta används i Go i dess analogi för loop.

Utanför for loop-initierare (som har en speciell användning av semikolon), kan kommatecken användas istället för ett semikolon, särskilt när de aktuella satserna fungerar på samma sätt som ett loop-inkrement (t.ex. i slutet av en while-loop):

 
  ++  p  ,  ++  q  ;  ++  p  ;  ++  q  ; 

Makron

Kommat kan användas i förbehandlare makron för att utföra flera operationer inom ett enda syntaktisk uttryck.

En vanlig användning är att tillhandahålla anpassade felmeddelanden i misslyckade påståenden. Detta görs genom att skicka en uttryckslista i parentes till assertmakrot , där det första uttrycket är en felsträng och det andra uttrycket är villkoret som hävdas. Påståendemakrot matar ut sitt argument ordagrant om ett påståendefel . Följande är ett exempel:

 
 

    

     
     0  
    
               
         
    
     0
 #include  <stdio.h>  #include  <assert.h>  int  main  (  void  )  {  int  i  ;  for  (  i  =  ;  i  <=  9  ;  i  ++  )  {  hävda  (  ( "jag   är  för stor!"  ,  i  <=  4 )   );  printf  (  "i = %i  \n  "  ,  i  );  }  returnera  ;  } 

Produktion:

i = 0 i = 1 i = 2 i = 3 i = 4 hävda: assert.c:6: test_assert: Påstående `( "jag är för stor!", i <= 4 )' misslyckades. Avbruten

Men assert-makrot är vanligtvis inaktiverat i produktionskoden, så använd det endast för felsökningsändamål.

Skick

Kommat kan användas inom ett villkor (av ett if, while, do while eller for) för att tillåta extra beräkningar, särskilt anropa en funktion och använda resultatet, med block scoping :

       
     
 if  (  y  =  f  (  x  ),  y  >  x  )  {  ...  // påståenden som involverar x och y  } 

Ett liknande formspråk finns i Go , där syntaxen för if-satsen uttryckligen tillåter en valfri sats.

Komplex retur

Kommat kan användas i return-satser, för att tilldela en global variabel eller ut-parameter (som godkänts av referens). Detta formspråk antyder att uppdragen är en del av avkastningen, snarare än hjälpuppdrag i ett block som avslutas med den faktiska avkastningen. Till exempel, när du ställer in ett globalt felnummer:

 
         if  (  misslyckande  )  return  (  errno  =  EINVAL  ,  -1  ); 

Detta kan skrivas mer utförligt som:

  
      
     
 if  (  fel  )  {  errno  =  EINVAL  ;  returnera  -1  ;  } 

Undvik ett block

För korthetens skull kan kommatecken användas för att undvika ett block och tillhörande hängslen, som i:

          om  (  x  ==  1  )  y  =  2  ,  z  =  3  ; 
   
          om  (  x  ==  1  )  y  =  2  ,  z  =  3  ; 

istället för:

          om  (  x  ==  1  )  {  y  =  2  ;  z  =  3  ;} 
    
         
 om  (  x  ==  1  )  {  y  =  2  ;  z  =  3  ;  } 

Andra språk

I programmeringsspråken OCaml och Ruby används semikolon (";") för detta ändamål. JavaScript och Perl använder kommaoperatorn på samma sätt som C/C++ gör. I Java är kommatecken en avgränsare som används för att separera element i en lista i olika sammanhang. Det är inte en operatör och utvärderar inte till det sista elementet i listan.

Se även

Bibliografi

  • Ramajaran, V. (1994), Datorprogrammering i C , New Delhi: Prentice Hall of India
  • Dixit, JB (2005), Grunderna för datorer och programmering i C , New Delhi: Laxmi Publications
  • Kernighan, Brian W.; Ritchie, Dennis M. (1988), The C Programming Language (2:a upplagan), Englewood Cliffs, NJ: Prentice Hall

externa länkar