Home > Net >  How for() works internally in c?
How for() works internally in c?

Time:10-04

I have noticed that if you pass a local variable, it can change it's value even though you didn't pass it by adress.

I have 2 questions: is for() a function or a macro? I want to see how it was written.

How can it change the value, without an adress?

int main()
{
    int i = 0;
    for(; i < 5; i  );
    /* i is 5 now. How? */
    return 0;
}

CodePudding user response:

You are confusing two things, "how for works" (which isn't your actual problem), and variable scope (which is).

Consider:

#include <stdio.h>

int main()
{
    int i = 0;

    printf( "Address of i outside the loop: %p\n", &i );

    for ( int i = 0; i < 5;   i ) // this "shadows" i
    {
        printf( "Address of i inside the loop: %p\n", &i );
    }
}

You will see that the i inside the loop is at a different address. There are two variables named i here, and inside the for loop, the one declared at the beginning of the program is not visible.

This has nothing to do with how for works; it would be the same here:

#include <stdio.h>

int main()
{
    int i = 0;

    printf( "Address of i outside the block: %p\n", &i );

    {
        int i = 0; // this "shadows" i
        printf( "Address of i inside the block: %p\n", &i );
    }
}

You are looking at a "shadowed" variable: Inside the for loop / code block, i means something other than outside.

If you write this:

#include <stdio.h>

int main()
{
    int i = 0;

    printf( "Address of i outside the loop: %p\n", &i );

    for ( i = 0; i < 5;   i ) // does NOT "shadow" i
    {
        printf( "Address of i inside the loop: %p\n", &i );
    }
}

...you don't redeclare i -- no int in the for statement, so there is only one declaration, and only one variable named i in the program.

for is not a function or a macro, but a keyword of the language. There is no convenient bit of code that would show you its inner workings, as what it does would be spread out across the various compiling stages (lexing, parsing, code generation). But as I showed above, what confuses you has nothing to do with for in the first place, but with variable scope. I hope the example snippets help you understanding the issue better.

CodePudding user response:

It is not very useful to know how it is implemented internally, it is easier if you think about how it can be implemented in an abstract syntax tree:

Your for loop can be implemented as

int i = 0;
while (i < 5)
{
     i = i   1;
}

For a similar code:

x = 0;
while (x < 10)
{
    print(x);
    x  = 1;
}
y = x   3;

The graphical representation is:

enter image description here

(Image taken from https://www.cs.toronto.edu/~david/course-notes/csc110-111/15-graphs/07-control-flow-graphs.html)

That is: Iterates executing the code of the left branch as long as the condition x < 10 is met, when the condition is no longer met it continues with the right branch (the rest of the code).

CodePudding user response:

I have noticed that if you pass a local variable, it can change it's value

That is because if we can't change values of local variables, it would be impossible to write functioning programs.

is for() a function or a macro?

It is neither, it is an iteration statement, one of the core building blocks of the language.

I want to see how it was written.

That doesn't make any sense, for the above reason. A for loop can generate all manner of machine code, including the compiler performing a complete loop unrolling and/or removing the loop entirely. For example if I add a printf("%d\n", i) at the bottom of your program, the whole loop when compiled on x86 gets replaced with mov esi, 5 = move the value 5 into a register (then print it). No loop is necessary.

A loop doesn't exist as written code, other than as a lexical element that the compiler treats in a certain way, according to the C standard.

How can it change the value, without an adress?

This has nothing to do with the loop as such but the i expression, which is guaranteed to update the variable "as per assignment", similar to i=i 1. No address is needed, the variable is written to directly.

CodePudding user response:

your loop is an equivalen of:

int main(void)
{
    int i = 0;

    loop:

    if(!(i < 5)) goto loop_exit;
    i  ;
    goto loop;

    loop_exit:

    printf("%d\n", i);
}

CodePudding user response:

Judging by the comment you attached to your question, it seems that the real problem is that you don't understand what variable scope and shadowing are. So here is a short demonstration program:

#include <stdio.h>

int main( void )
{
    int i = 1000;

    printf( "Test 1: i now has the value: %d\n", i );

    for ( int i = 0; i < 5; i   )
    {
        printf( "Test 2: i now has the value: %d\n", i );
    }

    printf( "Test 3: i now has the value: %d\n", i );
}

This program has the following output:

Test 1: i now has the value: 1000
Test 2: i now has the value: 0
Test 2: i now has the value: 1
Test 2: i now has the value: 2
Test 2: i now has the value: 3
Test 2: i now has the value: 4
Test 3: i now has the value: 1000

In this program, I have declared two distinct int variables, both with the same name i. The second variable only exists inside the loop and when I use the identifier i inside the loop, it refers to this second variable. This means that the second variable i shadows the first variable, as long as it exists. As soon as you exit the loop, the second variable ceases to exist, so that it no longer shadows the first variable. That is why "Test 3" prints the value of the first variable again, which is 1000.

is for() a function or a macro?

It is neither a function nor a macro. It is a keyword, which means that it has a special meaning to the compiler. For this reason, it also does not have its own source code.

CodePudding user response:

You have to understand the concept of scope for a variable. Scope associates an identifier with an object. In less fancy words: a name with some memory.

In this code:

int main(void) {
    for (int i = 0; i < 5;   i) {
      ...
    }
    return 0;
}

the scope of i is the block of the for block (after the second {). This is a bit unusual in that normally the scope of an identifier starts after its declaration inside a block and ends at the enclosing }.

In this code:

int main(void) {
    int i = 0;
    for (;i < 5;   i) {
    }
    return 0;
}

i has block scope of the main's function block (the first {).

And then there's the case where the same identifier is used in different nested blocks (in C jargon this is called shadowing):

int main(void) {
    int i = 0;                    /* This i is in main's block scope. */
    for (int i = 0;i < 5;   i) {  /* This i shadows main's i. */
       frob(i);                   /* Uses i of the inner scope. */
    }
    /* Here i is from main's scope again. */
    return 0;
}

CodePudding user response:

Consider this:

int main() {
    int i = 1;  // function scope
    int j = 5;
    printf( "i = %d j = %d\n", i, j );

    {   // Begin local scope
        int i = 3; // local scope within "{}"
        printf( "i = %d j = %d\n", i, j );
        // There is no legitimate way to access the 'other' i in this scope.
        // The 'function scope' i stands in the shadows...

    }   // end local scope

    printf( "i = %d j = %d\n", i, j ); // function scope

    return 0;
}
i = 1 j = 5
i = 3 j = 5 // j is not being "shadowed"
i = 1 j = 5
  • Related