Related
From "C++ Primer" by Lippman,
When we define a variable, we should give it an initial value unless we are certain that the initial value will be overwritten before the variable is used for any other purpose. If we cannot guarantee that the variable will be reset before being read, we should initialize it.
What happens if an uninitialized variable is used in say an operation? Will it crash/ will the code fail to compile?
I searched the internet for answer to the same but there were differing 'claims'. Hence the following questions,
Will C and C++ standards differ in how they treat an uninitialized variable?
Regarding similar queries, how and where can I find an 'official' answer? Is it practical for an amateur to look up the C and C++ standards?
Q.1) What happens if an uninitialized variable is used in say an operation? Will it crash/ will the code fail to compile?
Many compilers try to warn you about code that improperly uses the value of an uninitialized variable. Many compilers have an option that says "treat warnings as errors". So depending on the compiler you're using and the option flags you invoke it with and how obvious it is that a variable is uninitialized, the code might fail to compile, although we can't say that it will fail to compile.
If the code does compile, and you try to run it, it's obviously impossible to predict what will happen. In most cases the variable will start out containing an "indeterminate" value. Whether that indeterminate value will cause your program to work correctly, or work incorrectly, or crash, is anyone's guess. If the variable is an integer and you try to do some math on it, you'll probably just get a weird answer. But if the variable is a pointer and you try to indirect on it, you're quite likely to get a crash.
It's often said that uninitialized local variables start out containing "random garbage", but that can be misleading, as evidenced by the number of people who post questions here pointing out that, in their program where they tried it, the value wasn't random, but was always 0 or was always the same. So I like to say that uninitialized local variables never start out holding what you expect. If you expected them to be random, you'll find that (at least on any given day) they're repeatable and predictable. But if you expect them to be predictable (and, god help you, if you write code that depends on it), then by jingo, you'll find that they're quite random.
Whether use of an uninitialized variable makes your program formally undefined turns out to be a complicated question. But you might as well assume that it does, because it's a case you want to avoid just as assiduously as you avoid any other dangerous, imperfectly-defined behavior.
See this old question and this other old question for more (much more!) information on the fine distinctions between undefined and indeterminate behavior in this case.
Q.2) Will C and C++ standards differ in how they treat an uninitialized variable?
They might differ. As I alluded to above, and at least in C, it turns out that not all uses of uninitialized local variables are formally undefined. (Some are merely "indeterminate".) But the passages quoted from the C++ standards by other answers here make it sound like it's undefined there all the time. Again, for practical purposes, the question probably doesn't matter, because as I said, you'll want to avoid it no matter what.
Q.3) Regarding similar queries, how and where can I find an 'official' answer? Is it practical for an amateur to look up the C and C++ standards?
It is not always easy to obtain copies of the standards (let alone official ones, which often cost money), and the standards can be difficult to read and to properly interpret, but yes, given effort, anyone can obtain, read, and attempt to answer questions using the standards. You might not always make the correct interpretation the first time (and you may therefore need to ask for help), but I wouldn't say that's a reason not to try. (For one thing, anyone can read any document and end up not making the correct interpretation the first time; this phenomenon is not limited to amateur programmers reading complex language standards documents!)
C++
The C++ Standard, [dcl.init], paragraph 12 [ISO/IEC 14882-2014], states the following:
If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced. If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:
(end quote)
So using an uninitialized variable will result in undefined behavior.
Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior. The program may give your expected output or it may crash.
C
The C Standard, 6.7.9, paragraph 10, specifies [ISO/IEC 9899:2011]
If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.
Uninitialized automatic variables or dynamically allocated memory has indeterminate values, which for objects of some types, can be a trap representation. Reading such trap representations is undefined behavior.
1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.
What happens if an uninitialized variable is used in say an operation?
It depends. If the operation uses the value of the variable, and the type of the variable and the expression aren't excepted from it, then the behaviour of the program is undefined.
If the value isn't used - such as in the case of sizeof operator, then nothing particular happens that wouldn't happen with an initialised variable.
Will C and C++ standards differ in how they treat an uninitialized variable?
They use different wording, but are essentially quite similar in this regard.
C defines the undefined behaviour of indeterminate values through the concept of "trap representation" and specifies types that are guaranteed to not have trap representations.
C++ doesn't define the concept of "trap representation", but rather lists exceptional cases where producing an indeterminate value doesn't result in undefined behaviour. These cases have some overlap with the exceptional types in C, but aren't exactly the same.
Regarding similar queries, how and where can I find an 'official' answer?
The official answer - if there is one - is always in the language standard document.
The standard says it is undefined.
However on a Unix or VMS based system (Gnu/Linux, UNIX, BSD, MS-Windows > XP or NT, MacOS > X) then the stack and heap are initialised to zero (this is done for security reasons. Now to make your code work.)
However if you go up and down the stack or free then malloc then the data will be random rubish. (there may be other causes of random rubish. Don't rely on undefined behaviours).
Could the program crash? (By this, you mean detect error at run-time.)
Probably not, but again this is undefined behaviour. A C interpreter may do this.
Note also, some C++ types have a constructor that does well-defined initialisation.
You have tagged both C and C++. In C, an uninitialized variable probably has junk bits. Often your compiler with put zero bits there, but you can not count on it. So if you use that variable without explicitly initializing, the result may be sensible and it may not. And strictly speaking this is undefined behavior, so anything at all may happen.
C++ has the same for simple variables, but there is an interesting exception: while a int x[3] contains junk, std::vector x(3) contains zeros.
From "C++ Primer" by Lippman,
When we define a variable, we should give it an initial value unless we are certain that the initial value will be overwritten before the variable is used for any other purpose. If we cannot guarantee that the variable will be reset before being read, we should initialize it.
What happens if an uninitialized variable is used in say an operation? Will it crash/ will the code fail to compile?
I searched the internet for answer to the same but there were differing 'claims'. Hence the following questions,
Will C and C++ standards differ in how they treat an uninitialized variable?
Regarding similar queries, how and where can I find an 'official' answer? Is it practical for an amateur to look up the C and C++ standards?
Q.1) What happens if an uninitialized variable is used in say an operation? Will it crash/ will the code fail to compile?
Many compilers try to warn you about code that improperly uses the value of an uninitialized variable. Many compilers have an option that says "treat warnings as errors". So depending on the compiler you're using and the option flags you invoke it with and how obvious it is that a variable is uninitialized, the code might fail to compile, although we can't say that it will fail to compile.
If the code does compile, and you try to run it, it's obviously impossible to predict what will happen. In most cases the variable will start out containing an "indeterminate" value. Whether that indeterminate value will cause your program to work correctly, or work incorrectly, or crash, is anyone's guess. If the variable is an integer and you try to do some math on it, you'll probably just get a weird answer. But if the variable is a pointer and you try to indirect on it, you're quite likely to get a crash.
It's often said that uninitialized local variables start out containing "random garbage", but that can be misleading, as evidenced by the number of people who post questions here pointing out that, in their program where they tried it, the value wasn't random, but was always 0 or was always the same. So I like to say that uninitialized local variables never start out holding what you expect. If you expected them to be random, you'll find that (at least on any given day) they're repeatable and predictable. But if you expect them to be predictable (and, god help you, if you write code that depends on it), then by jingo, you'll find that they're quite random.
Whether use of an uninitialized variable makes your program formally undefined turns out to be a complicated question. But you might as well assume that it does, because it's a case you want to avoid just as assiduously as you avoid any other dangerous, imperfectly-defined behavior.
See this old question and this other old question for more (much more!) information on the fine distinctions between undefined and indeterminate behavior in this case.
Q.2) Will C and C++ standards differ in how they treat an uninitialized variable?
They might differ. As I alluded to above, and at least in C, it turns out that not all uses of uninitialized local variables are formally undefined. (Some are merely "indeterminate".) But the passages quoted from the C++ standards by other answers here make it sound like it's undefined there all the time. Again, for practical purposes, the question probably doesn't matter, because as I said, you'll want to avoid it no matter what.
Q.3) Regarding similar queries, how and where can I find an 'official' answer? Is it practical for an amateur to look up the C and C++ standards?
It is not always easy to obtain copies of the standards (let alone official ones, which often cost money), and the standards can be difficult to read and to properly interpret, but yes, given effort, anyone can obtain, read, and attempt to answer questions using the standards. You might not always make the correct interpretation the first time (and you may therefore need to ask for help), but I wouldn't say that's a reason not to try. (For one thing, anyone can read any document and end up not making the correct interpretation the first time; this phenomenon is not limited to amateur programmers reading complex language standards documents!)
C++
The C++ Standard, [dcl.init], paragraph 12 [ISO/IEC 14882-2014], states the following:
If no initializer is specified for an object, the object is default-initialized. When storage for an object with automatic or dynamic storage duration is obtained, the object has an indeterminate value, and if no initialization is performed for the object, that object retains an indeterminate value until that value is replaced. If an indeterminate value is produced by an evaluation, the behavior is undefined except in the following cases:
(end quote)
So using an uninitialized variable will result in undefined behavior.
Undefined behavior means anything1 can happen including but not limited to the program giving your expected output. But never rely(or make conclusions based) on the output of a program that has undefined behavior. The program may give your expected output or it may crash.
C
The C Standard, 6.7.9, paragraph 10, specifies [ISO/IEC 9899:2011]
If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate.
Uninitialized automatic variables or dynamically allocated memory has indeterminate values, which for objects of some types, can be a trap representation. Reading such trap representations is undefined behavior.
1For a more technically accurate definition of undefined behavior see this where it is mentioned that: there are no restrictions on the behavior of the program.
What happens if an uninitialized variable is used in say an operation?
It depends. If the operation uses the value of the variable, and the type of the variable and the expression aren't excepted from it, then the behaviour of the program is undefined.
If the value isn't used - such as in the case of sizeof operator, then nothing particular happens that wouldn't happen with an initialised variable.
Will C and C++ standards differ in how they treat an uninitialized variable?
They use different wording, but are essentially quite similar in this regard.
C defines the undefined behaviour of indeterminate values through the concept of "trap representation" and specifies types that are guaranteed to not have trap representations.
C++ doesn't define the concept of "trap representation", but rather lists exceptional cases where producing an indeterminate value doesn't result in undefined behaviour. These cases have some overlap with the exceptional types in C, but aren't exactly the same.
Regarding similar queries, how and where can I find an 'official' answer?
The official answer - if there is one - is always in the language standard document.
The standard says it is undefined.
However on a Unix or VMS based system (Gnu/Linux, UNIX, BSD, MS-Windows > XP or NT, MacOS > X) then the stack and heap are initialised to zero (this is done for security reasons. Now to make your code work.)
However if you go up and down the stack or free then malloc then the data will be random rubish. (there may be other causes of random rubish. Don't rely on undefined behaviours).
Could the program crash? (By this, you mean detect error at run-time.)
Probably not, but again this is undefined behaviour. A C interpreter may do this.
Note also, some C++ types have a constructor that does well-defined initialisation.
You have tagged both C and C++. In C, an uninitialized variable probably has junk bits. Often your compiler with put zero bits there, but you can not count on it. So if you use that variable without explicitly initializing, the result may be sensible and it may not. And strictly speaking this is undefined behavior, so anything at all may happen.
C++ has the same for simple variables, but there is an interesting exception: while a int x[3] contains junk, std::vector x(3) contains zeros.
I know the concept of register variable and it's use cases but there are few questions in my mind based on what I have tried.
I cannot access the address of a register variable in C though I can do it C++! Why? Is there any issue in accessing the addressing of a register variable?
Suppose if I declare a string variable in C++ as register, then where will that variable be stored? What is the point in declaring the storage class of non-numeric data types such as 'string' in C++ to be register??
UPDATE:
I thought that C++ allows us to fetch the address of a register variable, as I was not getting any error in my program which is as follows:
#include<iostream>
#include<time.h>
using namespace std;
clock_t beg, en;
int main(){
int j, k=0;
beg=clock();
for(register int i=0;i<10000000;i++){
/*if(k==0){
cout<<&i<<endl; // if this code is uncommented, then C++ rejects the recommendation to make 'i' as register
k++;
}*/
}
en=clock();
cout<<en-beg<<endl;
cout<<&j<<endl<<&k;
return 0;
}
What I have observed is, if I make the variable 'i' as register and don't try to print the address using '&i' then C++ accepts the recommendation and stores 'i' in register, this can be infered from running time of for loop which will always be around 4-12 ms if 'i' is in register. But if I try to print address of variable 'i' then though I don't get any error but C++ rejects the recommendation and this can be infered from the time of execution of loop which is always more than 25 if i is not register!!
So, basically I cannot fetch address of a variable with storage class as register in both C as well as C++!! WHY?
C and C++ are different languages.
In C, you cannot take the address of a variable with register storage. Cf. C11 6.7.1/6:
A declaration of an identifier for an object with storage-class specifier register
suggests that access to the object be as fast as possible. The extent to which such
suggestions are effective is implementation-defined.
Footnote: The implementation may treat any register declaration simply as an auto declaration. [...]
In C++, register is a deprecated, meaningless keyword that has no effect (except perhaps serve as a compiler hint), and variables declared as register still just have automatic storage. In particular, C++ doesn't have a "register" storage class. (It just has the storage class specifier, inherited from C.) Cf. C++11, 7.1.1/3:
A register specifier is a hint to the implementation that the variable so declared will be heavily used. [ Note: The hint can be ignored and in most implementations it will be ignored if the address of the variable is taken. This use is deprecated [...]
Even in C nothing is actually guaranteed about how register storage is implemented (implementations are free to treat register as auto), but the language rules apply regardless.
First, let's take a look at the relevant standards. It's always possible that C and C++ have different meanings for this keyword.
C++ 2011 Section 7.1.1 Paragraphs 2 and 3:
The register specifier shall be applied only to names of variables declared in a block (6.3) or to function parameters (8.4). It specifies that the named variable has automatic storage duration (3.7.3). A variable declared without a storage-class-specifier at block scope or declared as a function parameter has automatic storage duration by default.
A register specifier is a hint to the implementation that the variable so declared will be heavily used. [ Note: The hint can be ignored and in most implementations it will be ignored if the address of the variable is taken. This use is deprecated (see D.2). — end note ]
C 2011 Section 6.7.1 Paragraph 6 and Footnote 121:
A declaration of an identifier for an object with storage-class specifier register suggests that access to the object be as fast as possible. The extent to which such suggestions are effective is implementation-defined.)
The implementation may treat any register declaration simply as an auto declaration. However, whether or not addressable storage is actually used, the address of any part of an object declared with storage-class specifier register cannot be computed, either explicitly (by use of the unary & operator as discussed in 6.5.3.2) or implicitly (by converting an array name to a pointer as discussed in 6.3.2.1). Thus, the only operators that can be applied to an array declared with storage-class specifier register are sizeof and _Alignof.
So, let's take away what we've learned here.
In C++, the register keyword has no meaning. It does function as a compiler hint, but it's suggested that most compilers will ignore that hint anyways.
In C, the register keyword retains a meaning. Here, we are not, for example, allowed to take the address of an object (see the quoted footnote). An implementation may ignore the register hint, and place the object in memory anyways, but the keyword does restrict what you can do with the object. These restrictions should enable a compiler to better optimize access to the object, but it's also possible (like it is suggested in the C++ case), that the compiler will be able to infer this anyways.
As to what you're seeing in practice:
We can see why you're getting the syntax error in C when you try to take the address of a register int, so let's move past that.
You claim to be seeing a performance difference in C++ depending on whether or not you use register. In this case, it would be good to show your test, because there may be problems in the test itself. If the full test is fine, then it certainly is possible that your compiler is using the hint to produce better code.
The code you've shown is certainly odd though. That's because a compiler under optimizations will likely just remove the entire for loop from the code. The for loop has no side-effects. It's likely (and preferred) that a compiler will return identical code (that is, no code) with for (int i=0; i<100; ++i){} and for (register int i=0; i<100; ++i) {}.
Taking the address of a variable will FORCE the compiler to store it in a memory (unless it's an architecure where registers has an address - I think the TI 9900 series processors were implemented this way, but it's a vague memory from ca 1984). If you have told the compiler to use a register, that makes it incompatible. Although the C++ standard seems to suggest that the compiler isn't obliged to tell you so, and can in fact ignore the register keyword.
C++11 draft n3337, section 7.1.1, bullet 3
A register specifier is a hint to the implementation that the variable so declared will be heavily used.
[ Note: The hint can be ignored and in most implementations it will be ignored if the address of the variable
is taken. This use is deprecated (see D.2). — end note ]
(Edit: Yes, the TMS 9900 does indeed have "registers in memory", so theoretically, you can have the address of a register in that architecture - but the architecture is much more that "registers live in memory (which has an address)" than "registers have addresses").
The basic answer is that, on most architectures, general purpose registers do not have memory addresses. In general, a pointer is simply a (virtual) memory address of the memory location containing the object. This is done of efficiency.
It would be possible to extend the concept of a pointer to point to memory or register. However, doing so would decrease program speed as the code to dereference a pointer would need to check what type of location is being pointer to.
Many aspects of C stem from a desire to allow single-pass compilation. Many early compilers would read a little source code, generate some assembly or machine code, forget most of what they just read, read a little more code, generate some more assembly/machine code, etc. If the compiler is generating machine code it may need to build up a list of back-patches for things like forward jumps, but a compiler could generate code for functions which were bigger than its available RAM.
Many machines have a few registers that could be dedicated to storing values, but a compiler would not be able to know what variables could be most usefully kept in registers at any given point in the code unless it knows how variables are going to be used later in the code. Given something like:
void test(void)
{
int i,j,*p;
p=&i;
i=j=0;
do
{
j++;
*p+=10;
j++;
...
a single-pass compiler would have no way of knowing whether it could safely keep j in a register across the access to *p. Flushing j to memory before the *p+=10; and reloading it after would negate most of the advantage of allocating a register to it, but a compiler skipped the flush and reload but the above code were followed by p=&j; it would have a problem. All loop passes after the first would need to keep j in memory while executing *p+=10;, but the compiler would have already forgotten the code that would be required for the second pass.
This issue was resolved by specifying that if a compiler is declared register, a compiler may safely generate code which assumes that no pointer-based accesses will affect it. The prohibition against taking the address was IMHO needlessly over-reaching (*) but it was simpler to describe than one which would allow the qualifier to be used in more circumstances.
(*)The semantics would be useful, even today, if register promised that a compiler could safely keep a variable in a register if it flushed it to memory when its address was taken, and held off on reloading it until the next time code used the variable, branched backward [via looping construct or goto], or entered a loop where the variable was used].
Precisely because it's a register. An address is an address of a memory location. If something is resident in a register it is by definition not in main memory.
In C, we cannot take the address of a variable with register storage. we need to store with normal variables name.
You can't take the address of a register variable, because it's not stored in RAM.
In C, we cannot use & to find out the address of a register variable but in C++ we can do the same. Why is it legal in C++ but not in C? Can someone please explain this concept in-depth.
Here's an excerpt from Section 6.7.1 (footnote 101) of the C99 standard (pdf):
The implementation may treat any register declaration simply as an auto declaration. However, whether or not addressable storage is actually used, the address of any part of an object declared with storage-class specifier register cannot be computed, either explicitly (by use of the unary & operator as discussed in 6.5.3.2) or implicitly (by converting an array name to a pointer as discussed in 6.3.2.1). Thus, the only operator that can be applied to an array declared with storage-class specifier register is sizeof.
And from Section 7.1.1, Paragraph 3 of the C++ standard (pdf):
A register specifier has the same semantics as an auto specifier together with a hint to the implementation that the object so declared will be heavily used. [Note: the hint can be ignored and in most implementations it will be ignored if the address of the object is taken. —end note]
Fun tidbits about register
The C++ group (WG21) wants to deprecate register:
The register keyword serves very little function, offering no more than a hint that a note says is typically ignored. It should be deprecated in this version of the standard, freeing the reserved name up for use in a future standard, much like auto has been re-used this time around for being similarly useless.
Notes from the March, 2009 meeting:
The consensus of the CWG was in favor of deprecating register.
Look what the C99 group (WG14) said about register (pdf) at a meeting:
General agreement to deprecate the “auto” keyword. Should we ask WG21 to go back to
the previous use of “register” (no address)? No, this will not fly with WG21.
The register keyword is a hint only and can be ignored. Most C++ compilers ignore it all of the time, but any C++ compiler will ignore it if you take the address of the variable, or create a reference to it.
On the other hand, a C++ compiler doesn't have to ignore "register" just because you take the variable's address. In theory the compiler could store it in a register and give you some magic pointer value that is somehow mapped to the register behind the scenes, but that would be a lot of work for very little gain, so no compiler (that I know of) does anything like that.
Since register is ignorable in C as well, I suspect that the explicit proscription against taking addresses of register variables was simply to alleviate C compilers from the burden of checking for this.
The relevant part of the C++ standard is 7.1.1.3:
A register specifier has the same semantics as an auto specifier together with a hint to the implementation that the object so declared will be heavily used. [Note: the hint can be ignored and in most implementations it will be ignored if the address of the object is taken. —end note]
Sorry about the super late answer.
The problem is that, in C, register originally meant storing values in a register which is why only int and char can be used for it. But with time and especially standard C++, it broadened to "fast access" rather than "in register of CPU".
So in C++, an array maybe a register type but we know that it is not possible to store arrays in a CPU register. Hence, it is logically okay to address a C++ register (in the above sense), but will still make no sense if the values are actually in a CPU register.
I assume that the keyword wouldn't have even made it into the language if it weren't for C compatibility. While I can not speak with any authority, if this is so, it seems to me there is a practical reason for it to be legal beyond simply a standard-enforced "the compiler is smarter than you" clause: C++ takes addresses of things without permission more readily than C does. Specifically: member functions, and references.
Because member functions require an implicit this parameter, it would be impossible to call them from an object declared register. In C, there is nothing prohibiting you from saying register struct X x;, so such language would have to be allowed in C++ [since C-compatibility is the whole reason the keyword even exists]. But if you prohibit calling member functions as well as taking addresses, that also covers the initial constructor call. In essence, it would not work on non-POD types. So you end up with one storage class specifier that is only valid for a small subset of the legal types, when all the rest can be used for anything.
You also could not create references to such objects, even though, technically, the compiler does not have to treat references as pointers. register int i; int& x; is not required to have space for two variables, but if you later do &x you end up with a pointer to i. So the initial construct has to be rendered illegal. While this seems like a non-issue, since references don't exist in C anyhow, returning to our previous point, POD types declared with the register specifier can no longer be copied. The compiler-provided copy constructor is of the form X::X(const X&) or X::X(X&) as appropriate.
So, in order to maintain C compatibility, they have to make register unique as a storage class specifier in that it does not apply to all types, and modify at least two different parts of the standard elsewhere [to specify that you can not create a reference to a variable declared with the register specifier, and to somehow work around the references for POD copying]. Or, they could just say "its okay to take the address" and let compilers decide whether or not to honor the requests. Something they were planning on doing anyhow.
A register variable doesn't have an address, it's held (at least it's supposed to be held) in a cpu register. Since the register modifier is nothing but a hint, if you force the compiler to generate code to extract it's address, the modifier will be ignored and you'll end up with a regular variable held in memory.
To directly answer your question, whichever one lets you take a register variable's address (your original post is contradicting itself..) lets you ignore your own hint and should at least issue a warning. IMO the correct implementation would be to disallow taking the address of a register variable.
The important thing to remember is that "register" is just a hint to the compiler (a pointless one at that; I've never seen any speed improvement, and most compilers probably just ignore it). C and C++ are both allowed to ignore your "advice" and keep the variable in memory. Of course, if you take the address of the variable, it will force it to assign a spot in memory.
C and C++ just have different rules about what you can do because they are different languages. The C++ designers decided to allow you to get the address of a register variable because it doesn't hurt anything; C doesn't allow you to do it because it would force it into memory.
Thinking about it more, C's restriction is probably for the same reason that variables had to be declared at the beginning of the block—the compiler can layout the memory for variables as it encounters them, without regard to how it's used later in the function.
This is an educated guess only, but I doubt that you can take the address of a register in C++ because such a think simply doesn't exist. C++ probably doesn't use a register in your particular case. Notice that the storage class qualifier register is only a hint to the compiler (and most if not all modern compilers happily ignore it completely).
C and C++ are two different languages, with a large common subset. That's why some things are different between them.
While I don't understand your question, register is (at least in C++) a hint that a variable might be accessed more frequently, and nothing more. In C, it means you can't take the address with the & unary operator, which made a certain amount of sense at the time. In the early days of C, it was expected that the compiler might not bother allocating memory for the variable, and so there would not necessarily be an address to take.
(Computers normally have registers, which are quick-access parts of the CPU, and hence the fastest storage to access. A variable might live in a register, rather than in memory, if that caused better performance.)
Nowadays, almost all compilers are sophisticated enough to do their own allocation better than the programmer can, so using register is almost always pointless.
In C/C++, why are globals and static variables initialized to default values?
Why not leave it with just garbage values? Are there any special
reasons for this?
Security: leaving memory alone would leak information from other processes or the kernel.
Efficiency: the values are useless until initialized to something, and it's more efficient to zero them in a block with unrolled loops. The OS can even zero freelist pages when the system is otherwise idle, rather than when some client or user is waiting for the program to start.
Reproducibility: leaving the values alone would make program behavior non-repeatable, making bugs really hard to find.
Elegance: it's cleaner if programs can start from 0 without having to clutter the code with default initializers.
One might then wonder why the auto storage class does start as garbage. The answer is two-fold:
It doesn't, in a sense. The very first stack frame page at each level (i.e., every new page added to the stack) does receive zero values. The "garbage", or "uninitialized" values that subsequent function instances at the same stack level see are really the previous values left by other method instances of your own program and its library.
There might be a quadratic (or whatever) runtime performance penalty associated with initializing auto (function locals) to anything. A function might not use any or all of a large array, say, on any given call, and it could be invoked thousands or millions of times. The initialization of statics and globals, OTOH, only needs to happen once.
Because with the proper cooperation of the OS, 0 initializing statics and globals can be implemented with no runtime overhead.
Section 6.7.8 Initialization of C99 standard (n1256) answers this question:
If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static storage duration is not initialized explicitly, then:
— if it has pointer type, it is initialized to a null pointer;
— if it has arithmetic type, it is initialized to (positive or unsigned) zero;
— if it is an aggregate, every member is initialized (recursively) according to these rules;
— if it is a union, the first named member is initialized (recursively) according to these rules.
Think about it, in the static realm you can't tell always for sure something is indeed initialized, or that main has started. There's also a static init and a dynamic init phase, the static one first right after the dynamic one where order matters.
If you didn't have zeroing out of statics then you would be completely unable to tell in this phase for sure if anything was initialized AT ALL and in short the C++ world would fly apart and basic things like singletons (or any sort of dynamic static init) would simple cease to work.
The answer with the bulletpoints is enthusiastic but a bit silly. Those could all apply to nonstatic allocation but that isn't done (well, sometimes but not usually).
In C, statically-allocated objects without an explicit initializer are initialized to zero (for arithmetic types) or a null pointer (for pointer types). Implementations of C typically represent zero values and null pointer values using a bit pattern consisting solely of zero-valued bits (though this is not required by the C standard). Hence, the bss section typically includes all uninitialized variables declared at file scope (i.e., outside of any function) as well as uninitialized local variables declared with the static keyword.
Source: Wikipedia