Operátor čárky - Comma operator

V programovacích jazycích C a C ++ je operátor čárky (představovaný tokenem , ) binární operátor, který vyhodnotí svůj první operand a zahodí výsledek, a poté vyhodnotí druhý operand a vrátí tuto hodnotu (a typ); mezi těmito hodnoceními je bod posloupnosti .

Použití tokenu čárky jako operátoru se liší od jeho použití ve voláních funkcí a definicích, deklarací proměnných, deklarací výčtu a podobných konstrukcích, kde funguje jako oddělovač .

Syntax

Operátor čárky odděluje výrazy (které mají hodnotu) způsobem analogickým tomu, jak středník ukončuje příkazy, a sekvence výrazů jsou uzavřeny v závorkách analogicky k tomu, jak jsou sekvence příkazů uzavřeny v závorkách: (a, b, c)je sekvence výrazů oddělená čárkami, který se vyhodnotí do posledního výrazu cwhile {a; b; c;}je posloupnost příkazů a nevyhodnotí se na žádnou hodnotu. Čárka může nastat pouze mezi dvěma výrazy - čárkami oddělenými výrazy - na rozdíl od středníku, který se vyskytuje na konci (neblokového) příkazu - středníky ukončují příkazy.

Operátor čárky má nejnižší prioritu jakéhokoli operátoru C a funguje jako posloupnost . V kombinaci čárky a středníku mají středníky nižší prioritu než čárky, protože středníky oddělují jednotlivé příkazy, ale čárky se vyskytují v příkazech, což odpovídá jejich použití jako běžné interpunkční znaménko: a, b; c, dje seskupeno, (a, b); (c, d)protože se jedná o dva samostatné příkazy.

Příklady

V tomto příkladu je rozdílné chování mezi druhým a třetím řádkem způsobeno tím, že operátor čárky má nižší prioritu než přiřazení. Poslední příklad se také liší, protože návratový výraz musí být plně vyhodnocen, než se funkce může vrátit.

/**
 *  Commas act as separators in this line, not as an operator.
 *  Results: a=1, b=2, c=3, i=0
 */
int a=1, b=2, c=3, i=0;

/**
 *  Assigns value of b into i.
 *  Commas act as separators in the first line and as an operator in the second line.
 *  Results: a=1, b=2, c=3, i=2
 */
int a=1, b=2, c=3;              
int i = (a, b);           
                      
/**
 *  Assigns value of a into i.
 *  Equivalent to: int i = a; int b;
 *  Commas act as separators in both lines.
 *  The braces on the second line avoid variable redeclaration in the same block,
 *  which would cause a compilation error.
 *  The second b declared is given no initial value.
 *  Results: a=1, b=2, c=3, i=1
 */
int a=1, b=2, c=3;                                
{ int i = a, b; }

/**
 *  Increases value of a by 2, then assigns value of resulting operation a + b into i.
 *  Commas act as separators in the first line and as an operator in the second line.
 *  Results: a=3, b=2, c=3, i=5
 */
int a=1, b=2, c=3;
int i = (a += 2, a + b);
          
/**
 *  Increases value of a by 2, then stores value of a to i, and discards unused
 *  values of resulting operation a + b.
 *  Equivalent to: (i = (a += 2)), a + b;
 *  Commas act as separators in the first line and as an operator in the third line.
 *  Results: a=3, b=2, c=3, i=3
 */
int a=1, b=2, c=3;
int i;
i = a += 2, a + b;

/**
 *  Assigns value of a into i.
 *  Commas act as separators in both lines.
 *  The braces on the second line avoid variable redeclaration in the same block,
 *  which would cause a compilation error.
 *  The second b and c declared are given no initial value.
 *  Results: a=1, b=2, c=3, i=1
 */
int a=1, b=2, c=3;
{ int i = a, b, c; }

/**
 *  Commas act as separators in the first line and as an operator in the second line.
 *  Assigns value of c into i, discarding the unused a and b values.
 *  Results: a=1, b=2, c=3, i=3
 */
int a=1, b=2, c=3;
int i = (a, b, c);

/**
 *  Returns 6, not 4, since comma operator sequence points following the keyword 
 *  return are considered a single expression evaluating to rvalue of final 
 *  subexpression c=6.
 *  Commas act as operators in this line.
 */
return a=4, b=5, c=6;

/**
 *  Returns 3, not 1, for same reason as previous example.
 *  Commas act as operators in this line.
 */
return 1, 2, 3;

/**
 *  Returns 3, not 1, still for same reason as above. This example works as it does
 *  because return is a keyword, not a function call. Even though compilers will 
 *  allow for the construct return(value), the parentheses are only relative to "value"
 *  and have no special effect on the return keyword.
 *  Return simply gets an expression and here the expression is "(1), 2, 3".
 *  Commas act as operators in this line.
 */
return(1), 2, 3;

Použití

Provozovatel čárky má relativně omezené případy použití. Protože zahodí svůj první operand, je obecně užitečný pouze tam, kde první operand má žádoucí vedlejší účinky, které musí být sekvenovány před druhým operandem. Dále, protože se zřídka používá mimo konkrétní idiomy a snadno se mýlí s jinými čárkami nebo středníkem, je potenciálně matoucí a náchylný k chybám. Existují však určité okolnosti, kdy se běžně používá, zejména v případě smyček a v SFINAE . U vestavěných systémů, které mohou mít omezené možnosti ladění, lze operátor čárky použít v kombinaci s makrem k bezproblémovému přepsání volání funkce, k vložení kódu těsně před voláním funkce.

Pro smyčky

Nejběžnějším použitím je povolení více příkazů přiřazení bez použití příkazu bloku, primárně při inicializaci a přírůstkových výrazech smyčky for . Toto je jediné idiomatické použití v základním programování C. V následujícím příkladu je významné pořadí inicializátorů smyčky:

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

Alternativním řešením tohoto problému v jiných jazycích je paralelní přiřazení , které umožňuje více přiřazení v rámci jednoho příkazu a také používá čárku, i když s odlišnou syntaxí a sémantikou. Toto se používá v Go v analogické smyčce for.

Mimo inicializátory smyčky (které mají speciální použití středníků) může být místo středníku použita čárka, zvláště když dotyčné příkazy fungují podobně jako přírůstek smyčky (např. Na konci smyčky while):

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

Makra

Čárku lze v makrech preprocesoru použít k provádění více operací v prostoru jediného syntaktického výrazu.

Jedno běžné použití je poskytovat vlastní chybové zprávy v neúspěšných tvrzeních. To se provádí předáním seznamu výrazů v závorkách do assertmakra, kde první výraz je chybový řetězec a druhý výraz je podmínka, která se uplatňuje. assertMakro předává svou argumentaci doslovně na selhání tvrzení. Následuje příklad:

#include <stdio.h>
#include <assert.h>

int main ( void )
{
    int i;
    for (i=0; i<=9; i++)
    {
        assert( ( "i is too big!", i <= 4 ) );
        printf("i = %i\n", i);
    }
    return 0;
}

Výstup:

i = 0
i = 1
i = 2
i = 3
i = 4
assert: assert.c:6: test_assert: Assertion `( "i is too big!", i <= 4 )' failed.
Aborted

Makro tvrzení je však v produkčním kódu obvykle zakázáno, proto jej používejte pouze pro účely ladění.

Stav

Čárku lze použít v rámci podmínky (typu if, while, do while nebo for), aby bylo možné povolit pomocné výpočty, zejména volání funkce a použití výsledku, s rozsahem bloku :

if (y = f(x), y > x) {
    ... // statements involving x and y
}

Podobný idiom existuje v Go , kde syntaxe příkazu if výslovně umožňuje volitelný příkaz.

Složitý návrat

Čárku lze použít v návratových příkazech k přiřazení globální proměnné nebo parametru out (předáno odkazem). Tento idiom naznačuje, že přiřazení jsou součástí návratu, nikoli pomocných přiřazení v bloku, který končí skutečným návratem. Například při nastavení globálního čísla chyby:

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

Toto lze napsat podrobněji jako:

if (failure) {
    errno = EINVAL;
    return -1;
}

Vyhněte se bloku

Pro stručnost lze čárku použít k zamezení blokování a souvisejících závorek, například v:

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

namísto:

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

Jiné jazyky

V programovacích jazycích OCaml a Ruby se pro tento účel používá středník (";"). JavaScript a Perl používají operátor čárky stejným způsobem jako C / C ++. V Javě je čárka oddělovač používaný k oddělení prvků v seznamu v různých kontextech. Není to operátor a nevyhodnocuje se k poslednímu prvku v seznamu.

Viz také

Reference

Bibliografie

  • Ramajaran, V. (1994), Computer Programming in C , New Delhi: Prentice Hall of India
  • Dixit, JB (2005), Základy počítačů a programování v C , New Delhi: Laxmi Publications
  • Kernighan, Brian W .; Ritchie, Dennis M. (1988), Programovací jazyk C (2. vydání), Englewood Cliffs, NJ: Prentice Hall

externí odkazy