Carpe diem (Felix's blog)

I am a happy developer

C/ObjC Block Quizzes

Apple introduced blocks (anonymous functions or lambdas) as C extensions for its parallel programming model Grand Central Dispatch. Unlike ordinary C functions, blocks can capture surrounding variable contexts. The captured variables are casts to const by default, and for mutable variables you can mark it with __block storage qualifier. However, there is a lot of pitfalls in __block variables. Can you identify all of them?

Testing environment

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/*
 * clang -Wall -fblocks -framework Foundation quiz.c -o quiz
 */
#include <stdio.h>
#include <Block.h>


typedef void (^BoringBlock)(void);
BoringBlock boringBlock;

void quiz_1 (void) {...}
void quiz_2 (void) {...}
...

int main (void)
{
    quiz_1()
    boringBlock();
    Block_release(boringBlock);
    ...

    return 0;
}

The above is compile configuration and the program structure of the quiz. You can download and test the code form Github.

Quiz 1

1
2
3
4
5
6
7
8
9
10
11
12
13
void quiz_1 (void)
{
    __block int x = 1;
    printf("x address is %p\n", &x);

    BoringBlock localBlock = ^{
        x++; // Dummy use of x
        printf("End of quiz 1\n\n");
    };
    boringBlock = Block_copy(localBlock);

    printf("after copy, x address is %p\n", &x);
}

What would be printed if we execute quiz_1() then boringBlock()? Would &x be printed in same address or different addresses?

Show answer

Quiz 2

1
2
3
4
5
6
7
8
9
10
11
12
void quiz_2 (void)
{
    __block int x = 1;

    BoringBlock localBlock = ^{
        printf("x is %d\n", x);
        printf("End of quiz 2\n\n");
    };
    boringBlock = Block_copy(localBlock);

    x++;
}

Now, if we change the variable x in quiz_2() scope, would captured variable x also changes its value?

Show answer

Quiz 3

1
2
3
4
5
6
7
8
9
10
11
12
13
void quiz_3 (void)
{
    __block int x = 1;
    __block int* ptr = &x;

    BoringBlock localBlock = ^{
        printf("x is %d, *ptr is %d\n", x, *ptr);
        printf("End of quiz 3\n\n");
    };
    boringBlock = Block_copy(localBlock);

    x++;
}

Would x and *ptr be the same value?

Show answer

Quiz 4

1
2
3
4
5
6
7
8
9
10
void quiz_4(void)
{
    __block int x[1] = {1};

    void (^localBlock)(void) = ^{
        printf("x[0] is %d\n", x[0]);
        printf("End of quiz 4\n\n");
    }
    x[0] = 2;
}

What about array?

Show answer

Quiz 5

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
BoringBlock quiz_5(void)
{
    __block int x = 1;

    printf("x address is %p\n", &x);

    BoringBlock localBlock = ^{
        x++;
        printf("x is %d, &x is %p\n", x, &x);
    };
    boringBlock = Block_copy(localBlock);
    printf("x address is %p\n", &x);

    BoringBlock retBlock = Block_copy(localBlock);
    printf("x address is %p\n", &x);

    return retBlock;
}

Block execution:

1
2
3
4
5
6
    BoringBlock retBlock = quiz_5();
    boringBlock();
    retBlock();
    Block_release(boringBlock);
    Block_release(retBlock);
    printf("End of quiz 5\n\n");

What if we copied the block twice. Would the address change twice also?

Show answer

References

Source code:

You can download source code of this quiz from Github.

Comments