Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What does it mean by C requires "all variables to be initialized at the beginning of the scope"

Tags:

c

I'm learning about the difference between C++ and C and one of them is unlike C++, C does not allow a variable to be defined anywhere except at the beginning of the scope (from Thinking in C++)

The author gave an example where it would work in C++ but not in C, saying that retval has to be defined before the cout

//: C06:DefineInitialize.cpp
// Defining variables anywhere
#include "../require.h"
#include <iostream>
#include <string>
using namespace std;
class G {
  int i;
  public:
    G(int ii);
};
G::G(int ii) { i = ii; }
int main() {
  cout << "initialization value? ";
  int retval = 0;
  cin >> retval;
  require(retval != 0);
  int y = retval + 3;
  G g(y);
} ///:~

However when I run this code, which is similar to test, it still works?

#include <stdlib.h>
#include <stdio.h>

int main() {
    printf("Hello\n");
    int i;
    i = 0;
    exit(0);
}
like image 752
them8inchar Avatar asked Dec 14 '22 08:12

them8inchar


1 Answers

C does not allow a variable to be defined anywhere except at the beginning of the scope

This hasn't been true for 20 years, but 20 years ago is when Thinking In C++ was last revised.


When someone says "I'm programming in C" the question is then "which version of C?" There is a standard, but it has had several major revisions, and many non-standard extensions.

Prior to 1999, C required you to declare variables only at the start of the scope. In 1999 the standard changed to allow variable declarations anywhere you like.

C compilers can be configured to comply to various standards and extensions. Many C compilers will default to C99 or C11, often with extensions. The very common clang compiler currently defaults to C11 with GNU extensions. You can select which standard with -std. For example, if you want to see your code in C89: clang -std=c99.

Compiling your code using the C89 standard Thinking In C++ would have been written to, and because -Wall doesn't mean "all warnings" enough flags to get the compiler to issue warnings, gives us the warning we expect.

$ cc -Wall -Wextra -pedantic -std=c89 test.c
test.c:6:9: warning: ISO C90 forbids mixing declarations and code [-Wdeclaration-after-statement]
    int i;
        ^
1 warning generated.

With -std=c99 there's no problem.

$ cc -Wall -Wextra -pedantic -std=c99 test.c

When learning C, I'd strongly advise to avoid extensions, write to the standard, and turn on lots of warnings. -std=c11 is a good choice for the moment.


A problem with a lot of material on C and C++ is the C standards have changed over the last 40+ years, and a lot of material is out of date.

Here's a brief history of the fault lines.

1978 introduces K&R C. Named for Brian Kernighan and Dennis Ritchie who authored The C Programming Language aka "K&R". A this point there was no standard for C.

You'll still see this legacy in K&R style function declarations where the type is separate

int foo(s, f, b)
  char* s;
  float f;
  struct Baz * b;
{
  return 5;
}

1989 brings the first C standard which goes by many names: ANSI C / ISO C / C89. Many features are added. Function prototypes as we know them today are introduced. Today, just about every C compiler will comply to C89.

And yes, variables must be defined at the beginning of the scope. This legacy carries on even in material produced today resulting in awkward blocks of declarations far away from where they're used.

1999 brings a major revision of the standard, C99. This adds inline functions, more types, variable-length arrays, one-line comments //, and the ability to declare variables anywhere you like.

The process of C compilers adopting C99 has been very slow and is still ongoing. But you can definitely rely on declaring variables where you like.

2011 brings C11 and 2018 brings C17 / C18. It's not relevant to go into their changes to the standard here, just be aware of them.

Finally, there are non-standard extensions. The major ones are POSIX, GCC, and Microsoft extensions. Many compilers implement POSIX extensions. Some compilers, such as clang, have adopted GCC extensions. While Microsoft extensions are typically only available for Microsoft compilers and often conflict with the standard. Be aware that a lot of material will use extensions without telling you resulting in code that only works on specific compilers.

C++ underwent a similar process of standardization, revision, and extension which is still ongoing. C++'s major versions are C++98, C++03, C++11, C++14, and C++17 and also have Gnu and Microsoft extensions.


Thinking In C++ was first published in 1995, so it would be written to C89 and non-standard C++. Its 2nd edition was published in 2000, just after C99. That's unlikely to have been enough time for the author to be comfortable with C99 conventions, and their readers would likely still be using C compilers which used C89 or even K&R standards.

Adoption of C and C++ standards by compilers can be very, very slow. You will still find a lot of material on C is written to C89.

like image 80
Schwern Avatar answered Jan 18 '23 22:01

Schwern