Notes and Talks/UJEP/UPC/03

Program flow control

Conversions:

main.c#include <stdio.h>

// Pre-C23 version:
// typedef char bool;
// #define true 1
// #define false 0

// binary print macro
#define CHAR_TO_BIN(c)                                                         \
    ((c) & 0x80 ? '1' : '0'), ((c) & 0x40 ? '1' : '0'),                        \
        ((c) & 0x20 ? '1' : '0'), ((c) & 0x10 ? '1' : '0'),                    \
        ((c) & 0x08 ? '1' : '0'), ((c) & 0x04 ? '1' : '0'),                    \
        ((c) & 0x02 ? '1' : '0'), ((c) & 0x01 ? '1' : '0')

// hex and bin
#define PRINT(TAG, VAL)                                                        \
    printf("%s = %02x | %c%c%c%c %c%c%c%c\n", TAG, (VAL), CHAR_TO_BIN(VAL));

#define NL printf("\n")

int main() {
    char a = 3, b = 8, c = false, d = true;

    PRINT("a", a);
    PRINT("b", b);
    PRINT("c", c);
    PRINT("d", d);
    NL;

    // Logical operators: AND, OR, NOT
    PRINT("a && b", a && b);
    PRINT("a || b", a || b);
    PRINT("    !b", !b);
    PRINT("    !c", !c);
    NL;

    // Bitwise operators: AND, OR, XOR, NOT, Left shift, Right shift
    PRINT("a & b", a & b);
    PRINT("a | b", a | b);
    PRINT("a ^ b", a ^ b);
    PRINT("a ^ d", a ^ d);
    NL;

    PRINT("~a    ", ~a);
    PRINT("a << 1", a << 1);
    PRINT("a >> 1", a >> 1);
    PRINT("-a    ", -a);
    PRINT("-a>> 1", -a >> 1);
    NL;

    // tourist traps!
    PRINT("1 ", ~a);
    PRINT("2 ", ~(unsigned char) a);
    PRINT("3 ", (unsigned char) (~a));
    PRINT("3 ", (signed char) (~a));

    return 0;
}

Conditions, switches:

main.c#include <stdio.h>

#include <limits.h>

// #define NDEBUG
// #include <assert.h>

int const MAXINT = 2147483647;

void if_example() {
    // assert(0);
    // assert(INT_MAX == MAXINT);

    if (INT_MAX == MAXINT) {
        printf("MAXINT is correct\n");
    } else {
        printf("MAXINT is incorrect\n");
    }

    if (INT_MAX == MAXINT)
        printf("MAXINT is correct\n");
    else
        printf("MAXINT is incorrect\n");

    printf("MAXINT is %scorrect\n", (INT_MAX == MAXINT) ? "" : "in");
    printf("MAXINT %s correct\n", (INT_MAX == MAXINT) ? "is" : "is not");

    int n = -42;
    // int n = INT_MAX + 1;
    if (n > 0) {
        printf("n is positive\n");
    } else if (n < 0) {
        printf("n is negative\n");
    } else {
        printf("n is zero\n");
    }
}

void switch_example(int n) {
    switch (n) {
    case 1:
        printf("n is one\n");
        break;
    case 2:
        printf("n is two\n");
        break;
    case 3:
        printf("n is three\n");
        // fall through
    case 4:
        printf("n is three or four\n");
        break;
    default:
        printf("n is something else\n");
    }
}

int main() {
    if_example();
    switch_example(1);
    switch_example(2);
    switch_example(3);
    switch_example(5);
    return 0;
}

Loops:

main.c#include <stdio.h>

void while_loop_example() {
    int i = 0;
    while (i < 5) {
        printf("While loop iteration: %d\n", i);
        i++;
    }
}

void do_while_loop_example() {
    int i = 0;
    do {
        printf("Do-while loop iteration: %d\n", i);
        i++;
    } while (i < 5);
}

void for_loop_example() {
    for (int i = 0; i < 50; i++) {
        if (i % 10)
            continue; // Skip non-multiples of 10
        printf("For loop iteration: %d\n", i);
    }
}

void nested_loops_example() {
    for (int i = 1; i <= 3; i++) {
        for (int j = 1; j <= 3; j++) {
            printf("Nested loop iteration: i=%d, j=%d\n", i, j);
        }
    }
}

void pre_post_increment_example() {
    int i = 0;
    printf("Post-increment: %d\n", i++);
    printf("Pre-increment: %d\n", ++i);
    printf("Post-increment: %d %d %d - ha!\n", i++, i++, i++);
}

void infinite_for_loop_with_break_example() {
    int i = 0;
    for (;;) {
        printf("Infinite loop with break. Iteration: %d\n", i);
        if (5 <= i)
            break;
        i++;
    }
}

void infinite_loop_example() {
    while (1) {
        printf("This is an infinite loop. Press Ctrl+C to stop.\n");
    }
}

int main() {
    while_loop_example();
    do_while_loop_example();
    for_loop_example();
    nested_loops_example();
    infinite_for_loop_with_break_example();
    pre_post_increment_example();
    // infinite_loop_example();

    return 0;
}

Handle SIGINT (^C):

main.c#include <signal.h>
#include <stdio.h>
#include <unistd.h>

volatile sig_atomic_t stop = 0;

void handle_sigint(int sig) {
    ++stop;
    // C23 needs:
    signal(sig, handle_sigint);
}

int main() {
    printf("Infinite loop ... Press Ctrl+C three times to stop.\n");

    signal(SIGINT, handle_sigint);

    while (stop < 3) {
        putchar('.');
        fflush(stdout);
        sleep(1);
    }

    printf("Ending...\n");

    return 0;
}

Command-line arguments

main.c#include <stdio.h>

int main(int argc, char* argv[]) {
    // int main(int argc, char** argv) {
    // NOT: int main(int argc, char argv[][]) {
    printf("Number of arguments: %d\n", argc);

    for (int i = 0; i < argc; i++) {
        printf("Argument %d: %s\n", i, argv[i]);
    }

    return 0;
}