2

Code-1: No warnings - No errors ... everything works fine

#include <stdio.h>

int main()
{
    int r = 1;
    printf("using %d\n", r);

    for (int k = 1; k <= 2; k++)
    {
       int r = r * 2;
    }

    return 0;
}

Code-2: Wrong

#include <stdio.h>

int main()
{
    int cnt = 1;
    printf("using %d\n", cnt);
    
    {
        int cnt = cnt * 2;
    }

    return 0;
}

compiler response:

'cnt' is used uninitialized in this function [-Werror=uninitialized]
       int cnt = cnt * 2;

So, I understand there is some difference between the loop and block in this case, but I am unable to figure out. Can anyone tell me how the scope of a variable works here?

Sai Sreenivas
  • 1,690
  • 1
  • 7
  • 16
  • cnt in the block is not assigned – Arjun U S Aug 14 '20 at 07:42
  • @ArjunUS so is `r` in the loop – Cid Aug 14 '20 at 07:42
  • I think it has something to do with how compiler was designed. check this link [why am I not getting an “used uninitialized” warning from gcc in this trivial example?](https://stackoverflow.com/questions/46465442/why-am-i-not-getting-an-used-uninitialized-warning-from-gcc-in-this-trivial-ex) – Arjun U S Aug 14 '20 at 07:50

1 Answers1

2

They both have exactly the same problem i.e. r and cnt are self-initialized in respective programs.

This is potentially undefined because of use of uninitialized variables (which has indeterminate value) if they happen to have trap representation.

gcc happens to detect it one case and doesn't in the other case. gcc has -Wuninitialized -Winit-self options but it still doesn't detect the first case even with these options. Regardless, the issue remains (and the same) in both.

P.P
  • 117,907
  • 20
  • 175
  • 238
  • Could you explain why in the first case, at the end of `int r = r * 2;` statement, the value of `r` is 0 ? Is it because of the indeterminate value? – Inian Aug 14 '20 at 08:24
  • 1
    Yes, 0 can be an indeterminate value too. In general, *when* exactly using an uninitialized variable is undefined is immaterial - because there's no sane way to interpret that code/program (this is not to confused with objects with static storage who are guaranteed to be initialized to 0 even if initializers aren't provided e.g. global variables, `static int i;` anywhere, etc). – P.P Aug 14 '20 at 08:28
  • Makes sense. So to summarize how should the behavior of the first case be interpreted now if its not a compiler bug? – Inian Aug 14 '20 at 08:53
  • 1
    The outer scope variables aren't particularly relevant to the question because they are not visible in the inner scope due to declarations of `r` & `cnt` (variables with same name). It's not a compiler bug per se because compilers aren't required to issue diagnostics (warnings/errors) for undefined behaviours. Specifically, compilers are required to issue diagnostics for constraint violations; for others like UBs, programmers errors, etc they may warn to be helpful - but not required to. – P.P Aug 14 '20 at 09:06
  • Thanks for your answer, so I have doubt, so what if I put ```printf("using %d\n", cnt);``` before the existing statement in the block, does this ```printf statement``` also cause undefined behaviour? I am asking is it valid to use outer scope variables in this block until another variable (with same name) is defined? – Sai Sreenivas Aug 14 '20 at 09:19
  • 1
    @SaiSreenivas Do you mean something like https://godbolt.org/z/Y8q8ME? Yes, the `printf` is OK here because at the point, there's just only one `cnt` (thus no overlapping scope involved). But beware that [UB can time-travel](https://stackoverflow.com/q/32132574/1275169) - if some parts of the program [unconditionally](https://stackoverflow.com/q/18385020/1275169) exhibits UB, the whole program is said to contain UB. – P.P Aug 14 '20 at 09:31
  • In gcc this line generates a warning with `-Wshadow` but I can't find any way to detect the uninitialized state. – stark Aug 14 '20 at 13:41