Can anyone tell me the effect that the below code has on memory?
My questions are:
In code 1, is the same memory location getting updated every
time in the loop?
In code 2, is new memory allocated as the variable is declared and assigned in for loop?
Code 1:
int num;long result;
for(int i=0;i<500;i++){
num = i;
result = num * num;
}
Code 2:
for(int i=0;i<500;i++){
int num = i;
long result = num * num;
}
In both cases only one num and one result instance will be created.
The only different is that on Code 2 num and result won't be accessible after the loop and the memory used to hold them can be reused for other members.
Important: Where you declare a local variable in your source code has very little impact on when the actual allocation and deallocation (for example push/pop on the stack) takes place. If at all, the variable might get optimized away entirely.
Where in your C code you allocate your local variable has most likely no impact on performance what-so-ever. Therefore, you should declare local variables where it gives the best possible readability.
In both cases, the compiler will deduce that num is completely superfluous and optimize it away. No memory will be allocated for it.
In code 2, the compiler will deduce that the local variable result isn't used anywhere in the program, and therefore it will most likely optimize away the whole of code 2 into nothing.
The machine code of code 1 will look something like this:
allocate room for i
allocate room for result
set i to 0
loop:
multiply i by i
store in result
if i is less than 500, jump to loop
Can anyone tell me the effect that the below code has on memory?
As others have mentioned, the answer to your question hugely depends on the compiler you are using.
[1] Assuming you intend to use result and num later in the loop for other computations as in:
for(int i=0; i<500; ++i){
int num = i;
long result = num * num;
// more operations using num and result, e.g. function calls, IO, etc.
}
, a modern compiler (gcc, llvm, mvc, icc) would be smart enough to optimise the two codes you provided to the same thing, thus in both codes the same "memory location" would be updated on each iteration.
I put "memory location" in quotes, as the variables can be promoted to registers, which, while strictly speaking are still memory, are a lot faster to access and thus a preferable location for frequently used variables.
The only difference between your codes is the scope of your variables, but you probably already know that.
If, conversly to [1], you don't intend to use your variables later, the compiler would probably detect that and just skip the loop, not generating any machine code for it, as it is redundant.
Related
#include <stdio.h>
int main()
{
for(int i=0;i<100;i++)
{
int count=0;
printf("%d ",++count);
}
return 0;
}
output of the above program is: 1 1 1 1 1 1..........1
Please take a look at the code above. I declared variable "int count=0" inside the for loop.
With my knowledge, the scope of the variable is within the block, so count variable will be alive up to for loop execution.
"int count=0" is executing 100 times, then it has to create the variable 100 times else it has to give the error (re-declaration of the count variable), but it's not happening like that — what may be the reason?
According to output the variable is initializing with zero every time.
Please help me to find the reason.
Such simple code can be visualised on http://www.pythontutor.com/c.html for easy understanding.
To answer your question, count gets destroyed when it goes outside its scope, that is the closing } of the loop. On next iteration, a variable of the same name is created and initialised to 0, which is used by the printf.
And if counting is your goal, print i instead of count.
The C standard describes the C language using an abstract model of a computer. In this model, count is created each time the body of the loop is executed, and it is destroyed when execution of the body ends. By “created” and “destroyed,” we mean that memory is reserved for it and is released, and that the initialization is performed with the reservation.
The C standard does not require compilers to implement this model slavishly. Most compilers will allocate a fixed amount of stack space when the routine starts, with space for count included in this fixed amount, and then count will use that same space in each iteration. Then, if we look at the assembly code generated, we will not see any reservation or release of memory; the stack will be grown and shrunk only once for the whole routine, not grown and shrunk in each loop iteration.
Thus, the answer is twofold:
In C’s abstract model of computing, a new lifetime of count begins and ends in each loop iteration.
In most actual implementations, memory is reserved just once for count, although implementations may also allocate and release memory in each iteration.
However, even if you know your C implementation allocates stack space just once per routine when it can, you should generally think about programs in the C model in this regard. Consider this:
for (int i = 0; i < 100; ++i)
{
int count = 0;
// Do some things with count.
float x = 0;
// Do some things with x.
}
In this code, the compiler might allocate four bytes of stack space to use for both count and x, to be used for one of them at a time. The routine would grow the stack once, when it starts, including four bytes to use for count and x. In each iteration of the loop, it would use the memory first for count and then for x. This lets us see that the memory is first reserved for count, then released, then reserved for x, then released, and then that repeats in each iteration. The reservations and releases occur conceptually even though there are no instructions to grow and shrink the stack.
Another illuminating example is:
for (int i = 0; i < 100; ++i)
{
extern int baz(void);
int a[baz()], b[baz()];
extern void bar(void *, void *);
bar(a, b);
}
In this case, the compiler cannot reserve memory for a and b when the routine starts because it does not know how much memory it will need. In each iteration, it must call baz to find how much memory is needed for a and how much for b, and then it must allocate stack space (or other memory) for them. Further, since the sizes may vary from iteration to iteration, it is not possible for both a and b to start in the same place in each iteration—one of them must move to make way for the other. So this code lets us see that a new a and a new b must be created in each iteration.
int count=0 is executing 100 times, then it has to create the variable 100 times
No, it defines the variable count once, then assigns it the value 0 100 times.
Defining a variable in C does not involve any particular step or code to "create" it (unlike for example in C++, where simply defining a variable may default-construct it). Variable definitions just associate the name with an "entity" that represents the variable internally, and definitions are tied to the scope where they appear.
Assigning a variable is a statement which gets executed during the normal program flow. It usually has "observable effects", otherwise the compiler is allowed to optimize it out entirely.
OP's example can be rewritten in a completely equivalent form as follows.
for(int i=0;i<100;i++)
{
int count; // definition of variable count - defined once in this {} scope
count=0; // assignment of value 0 to count - executed once per iteration, 100 times total
printf("%d ",++count);
}
Eric has it correct. In much shorter form:
Typically compilers determine at compile time how much memory is needed by a function and the offsets in the stack to those variables. The actual memory allocations occur on each function call and memory release on the function return.
Further, when you have variables nested within {curly braces} once execution leaves that brace set the compiler is free to reuse that memory for other variables in the function. There are two reasons I intentionally do this:
The variables are large but only needed for a short time so why make stacks larger than needed? Especially if you need several large temporary structures or arrays at different times. The smaller the scope the less chance of bugs.
If a variable only has a sane value for a limited amount of time, and would be dangerous or buggy to use out of that scope, add extra curly braces to limit the scope of access so improper use generates immediate compiler errors. Using unique names for each variable, even if the compiler doesn't insist on it, can help the debugger, and your mind, less confused.
Example:
your_function(int a)
{
{ // limit scope of stack_1
int stack_1 = 0;
for ( int ii = 0; ii < a; ++ii ) { // really limit scope of ii
stack_1 += some_calculation(i, a);
}
printf("ii=%d\n", ii); // scope error
printf("stack_1=%d\n", stack_1); // good
} // done with stack_1
{
int limited_scope_1[10000];
do_something(a,limited_scope_1);
}
{
float limited_scope_2[10000];
do_something_else(a,limited_scope_2);
}
}
A compiler given code like:
void do_something(int, int*);
...
for (int i=0; i<100; i++)
{
int const j=(i & 1);
doSomething(i, &j);
}
could legitimately replace it with:
void do_something(int, int*);
...
int const __compiler_generated_0 = 0;
int const __compiler_generated_1 = 1;
for (int i=0; i<100; i+=2)
{
doSomething(i, &compiler_generated_0);
doSomething(i+1, &compiler_generated_1);
}
Although a compiler would typically allocate space on the stack once for j, when the function was entered, and then not reuse the storage during the loop (or even the function), meaning that j would have the same address on every iteration of the loop, there is no requirement that the address remain constant. While there typically wouldn't be an advantage to having the address vary on different iterations, compilers are be allowed to exploit such situations should they arise.
Having recently switched to c, I've been told a thousand ways to Sunday that referencing a value that hasn't been initialized isn't good practice, and leads to unexpected behavior. Specifically, (because my previous language initializes integers as 0) I was told that integers might not be equal to zero when uninitialized. So I decided to put that to the test.
I wrote the following piece of code to test this claim:
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
int main(){
size_t counter = 0;
size_t testnum = 2000; //The number of ints to allocate and test.
for(int i = 0; i < testnum; i++){
int* temp = malloc(sizeof(int));
assert(temp != NULL); //Just in case there's no space.
if(*temp == 0) counter++;
}
printf(" %d",counter);
return 0;
}
I compiled it like so (in case it matters):
gcc -std=c99 -pedantic name-of-file.c
Based on what my instructors had said, I expected temp to point to a random integer, and that the counter would not be incremented very often. However, my results blow this assumption out of the water:
testnum: || code returns:
2 2
20 20
200 200
2000 2000
20000 20000
200000 200000
2000000 2000000
... ...
The results go on for a couple more powers of 10 (*2), but you get the point.
I then tested a similar version of the above code, but I initialized an integer array, set every even index to plus 1 of its previous value (which was uninitialized), freed the array, and then performed the code above, testing the same amount of integers as the size of the array (i.e. testnum). These results are much more interesting:
testnum: || code returns:
2 2
20 20
200 175
2000 1750
20000 17500
200000 200000
2000000 2000000
... ...
Based on this, it's reasonable to conclude that c reuses freed memory (obviously), and sets some of those new integer pointers to point to addresses which contain the previously incremented integers. My question is why all of my integer pointers in the first test consistently point to 0. Shouldn't they point to whatever empty spaces on the heap that my computer has offered the program, which could (and should, at some point) contain non-zero values?
In other words, why does it seem like all of the new heap space that my c program has access to has been wiped to all 0s?
As you already know, you are invoking undefined behavior, so all bets are off. To explain the particular results you are observing ("why is uninitialized memory that I haven't written to all zeros?"), you first have to understand how malloc works.
First of all, malloc does not just directly ask the system for a page whenever you call it. It has an internal "cache" from which it can hand you memory. Let's say you call malloc(16) twice. The first time you call malloc(16), it will scan the cache, see that it's empty, and request a fresh page (4KB on most systems) from the OS. It then splits this page into two chunks, gives you the smaller chunk, and saves the other chunk in its cache. The second time you call malloc(16), it will see that it has a large enough chunk in its cache, and allocate memory by splitting that chunk again.
freeing memory simply returns it to the cache. There, it may (or may not be) be merged with other chunks to form a bigger chunk, and is then used for other allocations. Depending on the details of your allocator, it may also choose to return free pages to the OS if possible.
Now the second piece of the puzzle -- any fresh pages you obtain from the OS are filled with 0s. Why? Imagine it simply handed you an unused page that was previously used by some other process that has now terminated. Now you have a security problem, because by scanning that "uninitialized memory", your process could potentially find sensitive data such as passwords and private keys that were used by the previous process. Note that there is no guarantee by the C language that this happens (it may be guaranteed by the OS, but the C specification doesn't care). It's possible that the OS filled the page with random data, or didn't clear it at all (especially common on embedded devices).
Now you should be able to explain the behavior you're observing. The first time, you are obtaining fresh pages from the OS, so they are empty (again, this is an implementation detail of your OS, not the C language). However, if you malloc, free, then malloc again, there is a chance that you are getting back the same memory that was in the cache. This cached memory is not wiped, since the only process that could have written to it was your own. Hence, you just get whatever data was previously there.
Note: this explains the behavior for your particular malloc implementation. It doesn't generalize to all malloc implementations.
First off, you need to understand, that C is a language that is described in a standard and implemented by several compilers (gcc, clang, icc, ...). In several cases, the standard mentions that certain expressions or operations result in undefined behavior.
What is important to understand is that this means you have no guarantees on what the behavior will be. In fact any compiler/implementation is basically free to do whatever it wants!
In your example, this means you cannot make any assumptions of when the uninitialized memory will contain. So assuming it will be random or contain elements of a previously freed object are just as wrong as assuming that it is zero, because any of that could happen at any time.
Many compilers (or OS's) will consistently do the same thing (such as the 0s you observer), but that is also not guaranteed.
(To maybe see different behaviors, try using a different compiler or different flags.)
Undefined behavior does not mean "random behavior" nor does it mean "the program will crash." Undefined behavior means "the compiler is allowed to assume that this never happens," and "if this does happen, the program could do anything." Anything includes doing something boring and predictable.
Also, the implementation is allowed to define any instance of undefined behavior. For instance, ISO C never mentions the header unistd.h, so #include <unistd.h> has undefined behavior, but on an implementation conforming to POSIX, it has well-defined and documented behavior.
The program you wrote is probably observing uninitialized malloced memory to be zero because, nowadays, the system primitives for allocating memory (sbrk and mmap on Unix, VirtualAlloc on Windows) always zero out the memory before returning it. That's documented behavior for the primitives, but it is not documented behavior for malloc, so you can only rely on it if you call the primitives directly. (Note that only the malloc implementation is allowed to call sbrk.)
A better demonstration is something like this:
#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
{
int *x = malloc(sizeof(int));
*x = 0xDEADBEEF;
free(x);
}
{
int *y = malloc(sizeof(int));
printf("%08X\n", *y);
}
return 0;
}
which has pretty good odds of printing "DEADBEEF" (but is allowed to print 00000000, or 5E5E5E5E, or make demons fly out of your nose).
Another better demonstration would be any program that makes a control-flow decision based on the value of an uninitialized variable, e.g.
int foo(int x)
{
int y;
if (y == 5)
return x;
return 0;
}
Current versions of gcc and clang will generate code that always returns 0, but the current version of ICC will generate code that returns either 0 or the value of x, depending on whether register EDX is equal to 5 when the function is called. Both possibilities are correct, and so generating code that always returns x, and so is generating code that makes demons fly out of your nose.
useless deliberations, wrong assumptions, wrong test. In your test every time you malloc sizeof int of the fresh memory. To see the that UB you wanted to see you should put something in that allocated memory and then free it. Otherwise you do not reuse it, you just leak it. Most of the OS-es clear all the memory allocated to the program before executing it for the security reasons (so when you start the program everything was zeroed or initialised to the static values).
Change your program to:
int main(){
size_t counter = 0;
size_t testnum = 2000; //The number of ints to allocate and test.
for(int i = 0; i < testnum; i++){
int* temp = malloc(sizeof(int));
assert(temp != NULL); //Just in case there's no space.
if(*temp == 0) counter++;
*temp = rand();
free(temp);
}
printf(" %d",counter);
return 0;
}
I want to write a C program whose memory will be constant. It can never allocate more memory than certain amount.
int main(){
int memory[512];
int i = 5;
i = i + 5;
memory[50] = i;
};
Notice that on this example i = 5 and i = i+5 will allocate memory. I want to completely avoid the internal memory allocation procedure (which I believe is kind of slow).´Is there a way to tell C to allocate it directly on my memory array?
int memory[512]; int i = 5;
By doing this you have already allocated memory. Even if you do not fill elements after 100, there will be still total allocations of 512 ints for variable memory and 1 int for variable i.
If you need dynamic allowcation you can check malloc() or calloc().
You should change "which I believe is kind of slow" to "I am certain that it will not affect program speed"
First, the "allocation" for local ("stack") variables is very very fast, and generally happens at compile-time when the function's stack frame is laid out. There is no overhead per variable at run-time, that's just not how it works.
Second, if you want to avoid having a variable such as int i; take up further stack space, then you must avoid having that declaration in the code.
You can use the "block" you allocated but it's going to be painful:
int space[512];
space[0] = 5;
space[0] += 5;
space[50] = space[0];
The above replicates your use of i but instead manually "allocates" space[0] in the array. Of course, the above very likely generates worse code than just having a plain i, all for the sake of saving one int's worth of stack space.
Use globally declared variables only.
This however is bad advise for other obvious reasons: https://stackoverflow.com/a/176166/694576
The likely allocation cost of int i = 5; and i = i + 5; is zero. Single int variables inside methods just don't have any appreciable allocation cost. The compiler has several options here:
It will strive where possible to do the arithmetic at compile time and eliminate the variable entirely (memory[50] = 10;), meaning that at run time both the allocation and the arithmetic have no cost.
It will strive where possible to put the variable in a CPU register (zero allocation cost but still takes time for the arithmetic).
Failing that, it will reserve space for the variable on the stack, which consists of decrementing the stack pointer by 513*sizeof(int) bytes instead of 512*sizeof(int) bytes. It still won't take extra time. The OS might be obliged to fetch an extra page of memory for the thread's stack but this is more-or-less a one-time cost.
I've been trying to get into the habit of defining trivial variables at the point they're needed. I've been cautious about writing code like this:
while (n < 10000) {
int x = foo();
[...]
}
I know that the standard is absolutely clear that x exists only inside the loop, but does this technically mean that the integer will be allocated and deallocated on the stack with every iteration? I realise that an optimising compiler isn't likely to do this, but it that guaranteed?
For example, is it ever better to write:
int x;
while (n < 10000) {
x = foo();
[...]
}
I don't mean with this code specifically, but in any kind of loop like this.
I did a quick test with gcc 4.7.2 for a simple loop differing in this way and the same assembly was produced, but my question is really are these two, according to the standard, identical?
Note that "allocating" automatic variables like this is pretty much free; on most machines it's either a single-instruction stack pointer adjustment, or the compiler uses registers in which case nothing needs to be done.
Also, since the variable remains in scope until the loop exits, there's absolutely no reason to "delete" (=readjust the stack pointer) it until the loop exits, I certainly wouldn't expect there to be any overhead per-iteration for code like this.
Also, of course the compiler is free to "move" the allocation out of the loop altogether if it feels like it, making the code equivalent to your second example with the int x; before the while. The important thing is that the first version is easier to read and more tighly localized, i.e. better for humans.
Yes, the variable x inside the loop is technically defined on each iteration, and initialized via the call to foo() on each iteration. If foo() produces a different answer each time, this is fine; if it produces the same answer each time, it is an optimization opportunity – move the initialization out of the loop. For a simple variable like this, the compiler typically just reserves sizeof(int) bytes on the stack — if it can't keep x in a register — that it uses for x when x is in scope, and may reuse that space for other variables elsewhere in the same function. If the variable was a VLA — variable length array — then the allocation is more complex.
The two fragments in isolation are equivalent, but the difference is the scope of x. In the example with x declared outside the loop, the value persists after the loop exits. With x declared inside the loop, it is inaccessible once the loop exits. If you wrote:
{
int x;
while (n < 10000)
{
x = foo();
...other stuff...
}
}
then the two fragments are near enough equivalent. At the assembler level, you'll be hard pressed to spot the difference in either case.
My personal point of view is that once you start worrying about such micro-optimisations, you're doomed to failure. The gain is:
a) Likely to be very small
b) Non-portable
I'd stick with code that makes your intention clear (i.e. declare x inside the loop) and let the compiler care about efficiency.
There is nothing in the C standard that says how the compiler should generate code in either case. It could adjust the stack pointer on every iteration of the loop if it fancies.
That being said, unless you start doing something crazy with VLAs like this:
void bar(char *, char *);
void
foo(int x)
{
int i;
for (i = 0; i < x; i++) {
char a[i], b[x - i];
bar(a, b);
}
}
the compiler will most likely just allocate one big stack frame at the beginning of the function. It's harder to generate code for creating and destroying variables in blocks instead of just allocating all you need at the beginning of the function.
Here len is at A[10] and i is at A[11]. Is there a way to catch these errors??
I tried compiling with gcc -Wall -W but no warnings are displayed.
int main()
{
int A[10];
int i, len;
len = sizeof(A) / sizeof(0[A]);
printf("Len = %d\n",len);
for(i = 0; i < len; ++i){
A[i] = i*19%7;
}
A[i] = 5;
A[i + 1] = 6;
printf("Len = %d i = %d\n",len,i);
return 0;
}
Output :
Len = 10
Len = 5 i = 6
You are accessing memory outside the bounds of the array; in C, there is no bounds checking done on array indices.
Accessing memory beyond the end of the array technically results in undefined behavior. This means that there are no guarantees about what happens when you do it. In your example, you end up overwriting the memory occupied by another variable. However, undefined behavior can also cause your application to crash, or worse.
Is there a way to catch these errors?
The compiler can catch some errors like this, but not many. It is often impossible to catch this sort of error at compile-time and report a warning.
Static analysis tools can catch other instances of this sort of error and are usually built to report warnings about code that is likely to cause this sort of error.
C does not generally do bounds-checking, but a number of people have implemented bounds-checking for C. For instance there is a patch for GCC at http://sourceforge.net/projects/boundschecking/. Of course bounds-checking does have some overhead, but it can often be enabled and disabled on a per-file basis.
The array allocation of A is adjacent in memory to i and len. Remember that when you address via an array, it's exactly like using pointers, and you're walking off the end of the array, bumping into the other stuff you put there.
C by default does not do bounds checking. You're expected to be careful as a programmer; in exchange you get speed and size benefits.
Usually external tools, like lint, will catch the problems via static code analysis. Some libraries, depending on compiler vendor, will add additional padding or memory protection to detect when you've walked off the end.
Lots of interesting, dangerous, and non-portable things reside in memory at "random spots." Most of the house keeping for heap memory allocations occur in memory locations before the one the compiler gives you.
The general rule is that if you didn't allocate or request it, don't mess with it.
i's location in memory is just past the end of A. That's not guaranteed with every compiler and every architecture, but most probably wouldn't have a reason to do it any other way.
Note that counting from 0 to 9, you have 10 elements.
Array indexing starts from 0. Hence the size of array is equal to one less than the declared value. You are overwriting the memory beyond what is allowed.
These errors may not be reported as warnings but you can use tools like prevent, sparrow, Klockworks or purify to find such "malpractices" if i may call them that.
The short answer is that local variables are al-located on stack, and indexing is just like *(ptr + index). So it could happen that the room for int y[N] is adjacent to the room for another int x; e.g. x is located after the last y. So, y[N-1] is this last y, while y[N] is the int past the last y, and in this case, by accident, it happens you get x (or whatever in your practical example). But it is absolutely not a sure fact what you can get going past the bounds of an array and so you can't rely on that. Even though undetected, it's a "index out of bound error", and a source of bugs.