In programming languages, scoping rules define how variables are bound to their scopes, determining their visibility and accessibility within a program. The two primary scoping strategies are static scoping (also known as lexical scoping) and dynamic scoping. Here, we’ll discuss both concepts with examples in the context of C programming.

1. Static Scoping (Lexical Scoping)

In static scoping, a variable’s scope is determined at compile-time based on its position in the source code. The block structure of the program defines where variables can be accessed.

Example:

#include <stdio.h>

void outer_function() {
    int x = 10;
    void inner_function() {
        printf("Static Scoping: x = %d\n", x);
    }
    inner_function();
}

int main() {
    outer_function();
    // Uncommenting the next line would result in a compilation error
    // inner_function(); // Error: 'inner_function' undeclared
    return 0;
}

In this example, x is declared within outer_function, and inner_function can access x because it is lexically enclosed within the scope of outer_function. Attempting to call inner_function outside outer_function results in a compilation error because it is out of scope.

Simpler Example of Static Scoping:

#include <stdio.h>

void outer_function() {
    int x = 10;
    printf("Static Scoping: x = %d\n", x);
}

int main() {
    outer_function();
    // Uncommenting the next line would result in a compilation error
    // printf("Static Scoping: x = %d\n", x); // Error: 'x' undeclared
    return 0;
}

Here, x is declared in outer_function and is not accessible outside of it. Attempting to access x in main results in a compilation error.

2. Dynamic Scoping

Dynamic scoping determines a variable’s scope at runtime based on the call stack. The scope is influenced by the sequence of function calls, and variables are resolved in the context of the calling functions.

While C does not natively support dynamic scoping, you can simulate its behavior using global variables.

Example:

#include <stdio.h>

int x = 10;

void outer_function() {
    printf("Dynamic Scoping: x = %d\n", x);
}

void inner_function() {
    printf("Dynamic Scoping: x = %d\n", x);
}

int main() {
    outer_function();
    // Change the value of x
    x = 20;
    inner_function();
    return 0;
}

In this example, x is a global variable, and both outer_function and inner_function can access and print its value. Changing x affects both functions, demonstrating how variable values depend on runtime behavior.

Simpler Example of Dynamic Scoping:

#include <stdio.h>

int x = 10;

void dynamic_function() {
    printf("Dynamic Scoping: x = %d\n", x);
}

int main() {
    dynamic_function();
    // Change the value of x
    x = 20;
    dynamic_function();
    return 0;
}

In this simpler example, x is global, and changes to its value are reflected in subsequent calls to dynamic_function.

Key Differences:

  • Static Scoping: Variable scope is determined at compile-time based on the program’s structure.
  • Dynamic Scoping: Variable scope is determined at runtime, depending on the function call stack.

Note: C primarily relies on static scoping. Dynamic scoping is more common in languages like Lisp and Perl. The examples provided for dynamic scoping in C are simulations using global variables, not true dynamic scoping.

# Written by Elliyas Ahmed