What does a && operator do when there is no left side in C?

后端 未结 3 730
爱一瞬间的悲伤
爱一瞬间的悲伤 2020-12-29 01:22

I saw a program in C that had code like the following:

static void *arr[1]  = {&& varOne,&& varTwo,&& varThree};

varOne: printf(\"On         


        
相关标签:
3条回答
  • 2020-12-29 01:32

    This is a gcc extension, known as "Labels as Values". Link to gcc documentation.

    In this extension, && is a unary operator that can be applied to a label. The result is a value of type void *. This value may later be dereferenced in a goto statement to cause execution to jump to that label. Also, pointer arithmetic is permitted on this value.

    The label must be in the same function; or in an enclosing function in case the code is also using the gcc extension of "nested functions".

    Here is a sample program where the feature is used to implement a state machine:

    #include <stdio.h>
    #include <stdlib.h>
    #include <time.h>
    
    int main(void)
    {
        void *tab[] = { &&foo, &&bar, &&qux };
    
        // Alternative method
        //ptrdiff_t otab[] = { &&foo - &&foo, &&bar - &&foo, &&qux - &&foo };
    
        int i, state = 0;
    
        srand(time(NULL));
    
        for (i = 0; i < 10; ++i)
        {
            goto *tab[state];
    
            //goto *(&&foo + otab[state]);
    
        foo:
            printf("Foo\n");
            state = 2;
            continue;
        bar:
            printf("Bar\n");
            state = 0;
            continue;
        qux:
            printf("Qux\n");
            state = rand() % 3;
            continue;
        }
    }
    

    Compiling and execution:

    $ gcc -o x x.c && ./x
    Foo
    Qux
    Foo
    Qux
    Bar
    Foo
    Qux
    Qux
    Bar
    Foo
    
    0 讨论(0)
  • 2020-12-29 01:54

    I'm not aware of any operator that works this way in C. Depending on the context, the ampersand in C can mean many different things.

    Address-Of operator

    Right before an lvalue, e.g.

    int j;
    int* ptr = &j;
    

    In the code above, ptr stores the address of j, & in this context is taking the address of any lvalue. The code below, would have made more sense to me if it was written that way.

    static int varOne;
    static int varTwo;
    static int varThree;
    
    static void *arr[1][8432] = { { &varOne,&varTwo, &varThree } };
    

    Logical AND

    The logical AND operator is more simple, unlike the operator above, it's a binary operator, meaning it requires a left and right operand. The way it works is by evaluating the left and right operand and returning true, iff both are true, or greater than 0 if they are not bool.

    bool flag = true;
    bool flag2 = false;
    if (flag && flag2) {
        // Not evaluated
    }
    flag2 = true;
    if (flag && flag2) {
       // Evaluated
    }
    

    Bitwise AND

    Another use of the ampersand in C, is performing a bitwise AND. It's similar as the logical AND operator, except it uses only one ampersand, and performs an AND operation at the bit level.

    Let's assume we have a number and that it maps to the binary representation shown below, the AND operation works like so:

    0 0 0 0 0 0 1 0
    1 0 0 1 0 1 1 0
    ---------------
    0 0 0 0 0 0 1 0
    

    In C++ land, things get more complicated. The ampersand can be placed after a type as to denote a reference type (you can think of it as a less powerful but safe kind of pointer), then things get even more complicated with 1) r-value reference when two ampersands are placed after a type. 2) Universal references when two ampersands are placed after a template type or auto deducted type.

    I think your code probably compiles only in your compiler due to an extension of some sorts. I was thinking of this https://en.wikipedia.org/wiki/Digraphs_and_trigraphs#C but I doubt that's the case.

    0 讨论(0)
  • 2020-12-29 01:58

    It's a gcc-specific extension, a unary && operator that can be applied to a label name, yielding its address as a void* value.

    As part of the extension, goto *ptr; is allowed where ptr is an expression of type void*.

    It's documented here in the gcc manual.

    You can get the address of a label defined in the current function (or a containing function) with the unary operator &&. The value has type void *. This value is a constant and can be used wherever a constant of that type is valid. For example:

    void *ptr;
    /* ... */
    ptr = &&foo;
    

    To use these values, you need to be able to jump to one. This is done with the computed goto statement, goto *exp;. For example,

    goto *ptr;
    

    Any expression of type void * is allowed.

    As zwol points out in a comment, gcc uses && rather than the more obvious & because a label and an object with the same name can be visible simultaneously, making &foo potentially ambiguous if & means "address of label". Label names occupy their own namespace (not in the C++ sense), and can appear only in specific contexts: defined by a labeled-statement, as the target of a goto statement, or, for gcc, as the operand of unary &&.

    0 讨论(0)
提交回复
热议问题