How does c find at run time the size of array? where is the information about array size or bounds of array stored ?
sizeof(array) is implemented entirely by the C compiler. By the time the program gets linked, what looks like a sizeof() call to you has been converted into a constant.
Example: when you compile this C code:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv) {
int a[33];
printf("%d\n", sizeof(a));
}
you get
.file "sz.c"
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, #function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $164, %esp
movl $132, 4(%esp)
movl $.LC0, (%esp)
call printf
addl $164, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.1.2 (Gentoo 4.1.2 p1.1)"
.section .note.GNU-stack,"",#progbits
The $132 in the middle is the size of the array, 132 = 4 * 33. Notice that there's no call sizeof instruction - unlike printf, which is a real function.
sizeof is pure compile time in C++ and C prior to C99. Starting with C99 there are variable length arrays:
// returns n + 3
int f(int n) {
char v[n + 3];
// not purely a compile time construct anymore
return sizeof v;
}
That will evaluate the sizeof operand, because n is not yet known at compile time. That only applies to variable length arrays: Other operands or types still make sizeof compute at compile time. In particular, arrays with dimensions known at compile time are still handled like in C++ and C89. As a consequence, the value returned by sizeof is not a compile time constant (constant expression) anymore. You can't use it where such a value is required - for example when initializing static variables, unless a compiler specific extension allows it (the C Standard allows an implementation to have extensions to what it treats as constant).
sizeof() will only work for a fixed size array (which can be static, stack based or in a struct).
If you apply it to an array created with malloc (or new in C++) you will always get the size of a pointer.
And yes, this is based on compile time information.
sizeof gives the size of the variable, not the size of the object that you're pointing to (if there is one.) sizeof(arrayVar) will return the array size in bytes if and only if arrayVar is declared in scope as an array and not a pointer.
For example:
char myArray[10];
char* myPtr = myArray;
printf("%d\n", sizeof(myArray)) // prints 10
printf("%d\n", sizeof(myPtr)); // prints 4 (on a 32-bit machine)
sizeof(Array) is looked up at compile time, not at run time. The information is not stored.
Are you perhaps interested in implementing bounds checking? If so, there are a number of different ways to go about that.
Related
How does c find at run time the size of array? where is the information about array size or bounds of array stored ?
sizeof(array) is implemented entirely by the C compiler. By the time the program gets linked, what looks like a sizeof() call to you has been converted into a constant.
Example: when you compile this C code:
#include <stdlib.h>
#include <stdio.h>
int main(int argc, char** argv) {
int a[33];
printf("%d\n", sizeof(a));
}
you get
.file "sz.c"
.section .rodata
.LC0:
.string "%d\n"
.text
.globl main
.type main, #function
main:
leal 4(%esp), %ecx
andl $-16, %esp
pushl -4(%ecx)
pushl %ebp
movl %esp, %ebp
pushl %ecx
subl $164, %esp
movl $132, 4(%esp)
movl $.LC0, (%esp)
call printf
addl $164, %esp
popl %ecx
popl %ebp
leal -4(%ecx), %esp
ret
.size main, .-main
.ident "GCC: (GNU) 4.1.2 (Gentoo 4.1.2 p1.1)"
.section .note.GNU-stack,"",#progbits
The $132 in the middle is the size of the array, 132 = 4 * 33. Notice that there's no call sizeof instruction - unlike printf, which is a real function.
sizeof is pure compile time in C++ and C prior to C99. Starting with C99 there are variable length arrays:
// returns n + 3
int f(int n) {
char v[n + 3];
// not purely a compile time construct anymore
return sizeof v;
}
That will evaluate the sizeof operand, because n is not yet known at compile time. That only applies to variable length arrays: Other operands or types still make sizeof compute at compile time. In particular, arrays with dimensions known at compile time are still handled like in C++ and C89. As a consequence, the value returned by sizeof is not a compile time constant (constant expression) anymore. You can't use it where such a value is required - for example when initializing static variables, unless a compiler specific extension allows it (the C Standard allows an implementation to have extensions to what it treats as constant).
sizeof() will only work for a fixed size array (which can be static, stack based or in a struct).
If you apply it to an array created with malloc (or new in C++) you will always get the size of a pointer.
And yes, this is based on compile time information.
sizeof gives the size of the variable, not the size of the object that you're pointing to (if there is one.) sizeof(arrayVar) will return the array size in bytes if and only if arrayVar is declared in scope as an array and not a pointer.
For example:
char myArray[10];
char* myPtr = myArray;
printf("%d\n", sizeof(myArray)) // prints 10
printf("%d\n", sizeof(myPtr)); // prints 4 (on a 32-bit machine)
sizeof(Array) is looked up at compile time, not at run time. The information is not stored.
Are you perhaps interested in implementing bounds checking? If so, there are a number of different ways to go about that.
This question already has answers here:
Printing pointer addresses in C [two questions]
(5 answers)
Closed 5 years ago.
I have the following question. Why is there a difference in the addresses of the two pointers in following example? This is the full code:
#include <stdio.h>
#include <stdlib.h>
void *mymalloc(size_t bytes){
void * ptr = malloc(bytes);
printf("Address1 = %zx\n",(size_t)&ptr);
return ptr;
}
void main (void)
{
unsigned char *bitv = mymalloc(5);
printf("Address2 = %zx\n",(size_t)&bitv);
}
Result:
Address1 = 7ffe150307f0
Address2 = 7ffe15030810
It's because you are printing the address of the pointer variable, not the pointer. Remove the ampersand (&) from bitv and ptr in your printfs.
printf("Address1 = %zx\n",(size_t)ptr);
and
printf("Address2 = %zx\n",(size_t)bitv);
Also, use %p for pointers (and then don't cast to size_t)
WHY?
In this line of code:
unsigned char *bitv = mymalloc(5);
bitv is a pointer and its value is the address of the newly allocated block of memory. But that address also needs to be stored, and &bitv is the address of the where that value is stored. If you have two variables storing the same pointer, they will still each have their own address, which is why &ptr and &bitv have different values.
But, as you expected, ptr and bitv will have the same value when you change your code.
Why is there a difference in the addresses of the two pointers
Because the two pointers are two different pointer(-variable)s, each having it's own address.
The value those two pointer(-variable)s carry in fact are the same.
To prove this print their value (and not their address) by changing:
printf("Address1 = %zx\n",(size_t)&ptr);
to be
printf("Address1 = %p\n", (void*) ptr);
and
printf("Address2 = %zx\n",(size_t)&bitv);
to be
printf("Address2 = %p\n", (void*) bitv);
In your code you used to print pointer's address following code:
printf("%zx", (size_t)&p);
It doesn't print address of variabele it's pointing to, it prints address of pointer.
You could print address using '%p' format:
printf("%p", &n); // PRINTS ADDRESS OF 'n'
There's an example which explains printing addresses
int n;
int *v;
n = 54;
v = &n;
printf("%p", v); // PRINTS ADDRESS OF 'n'
printf("%p", &v); // PRINTS ADDRESS OF pointer 'v'
printf("%p", &n); // PRINTS ADDRESS OF 'n'
printf("%d", *v); // PRINTS VALUE OF 'n'
printf("%d", n); // PRINTS VALUE OF 'n'
So your code should be written like this:
void * get_mem(int size)
{
void * buff = malloc(size); // allocation of memory
// buff is pointing to result of malloc(size)
if (!buff) return NULL; //when malloc returns NULL end function
//else print address of pointer
printf("ADDRESS->%p\n", buff);
return buff;
}
int main(void)
{
void * buff = get_mem(54);
printf("ADDRESS->%p\n", buff);
free(buff);
return 0;
}
(In addition to other answers, which you would read first and probably should help you more ...)
Read a good C programming book. Pointers and addresses are very difficult to explain, and I'm not even trying to. So the address of a pointer &ptr is generally not the same as the value of a pointer (however, you could code ptr= &ptr; but you often don't want to do that)... Look also at the picture explaining virtual address space.
Then read more documentation about malloc: malloc(3) Linux man page, this reference documentation, etc... Here is fast, standard conforming, but disappointing implementation of malloc.
read also documentation about printf: printf(3) man page, printf reference, etc... It should mention %p for printing pointers...
Notice that you don't print a pointer (see Alk's answer), you don't even print its address (of an automatic variable on the call stack), you print some cast to size_t (which might not have the same bit width as a pointer, even if on my Linux/x86-64 it does).
Read also more about C dynamic memory allocation and about pointer aliasing.
At last, read the C11 standard specification n1570.
(I can't believe why you would expect the two outputs to be the same; actually it could happen if a compiler is optimizing the call to mymalloc by inlining a tail call)
So I did not expect the output to be the same in general. However, with gcc -O2 antonis.c -o antonis I've got (with a tiny modification of your code)....
a surprise
However, if you declare the first void *mymalloc(size_t bytes) as a static void*mymalloc(size_t bytes) and compile with GCC 7 on Linux/Debian/x86-64 with optimizations enabled, you do get the same output; because the compiler inlined the call and used the same location for bitv and ptr; here is the generated assembler code with gcc -S -O2 -fverbose-asm antonis.c:
.section .rodata.str1.1,"aMS",#progbits,1
.LC0:
.string "Address1 = %zx\n"
.LC1:
.string "Address2 = %zx\n"
.section .text.startup,"ax",#progbits
.p2align 4,,15
.globl main
.type main, #function
main:
.LFB22:
.cfi_startproc
pushq %rbx #
.cfi_def_cfa_offset 16
.cfi_offset 3, -16
# antonis.c:5: void * ptr = malloc(bytes);
movl $5, %edi #,
# antonis.c:11: {
subq $16, %rsp #,
.cfi_def_cfa_offset 32
# antonis.c:6: printf("Address1 = %zx\n",(size_t)&ptr);
leaq 8(%rsp), %rbx #, tmp92
# antonis.c:5: void * ptr = malloc(bytes);
call malloc#PLT #
# antonis.c:6: printf("Address1 = %zx\n",(size_t)&ptr);
leaq .LC0(%rip), %rdi #,
# antonis.c:5: void * ptr = malloc(bytes);
movq %rax, 8(%rsp) # tmp91, ptr
# antonis.c:6: printf("Address1 = %zx\n",(size_t)&ptr);
movq %rbx, %rsi # tmp92,
xorl %eax, %eax #
call printf#PLT #
# antonis.c:13: printf("Address2 = %zx\n",(size_t)&bitv);
leaq .LC1(%rip), %rdi #,
movq %rbx, %rsi # tmp92,
xorl %eax, %eax #
call printf#PLT #
# antonis.c:14: }
addq $16, %rsp #,
.cfi_def_cfa_offset 16
popq %rbx #
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE22:
.size main, .-main
BTW, if I compile your unmodified source (without static) with gcc -fwhole-program -O2 -S -fverbose-asm I'm getting the same assembler as above.
If you don't add static and don't compile with -fwhole-program the two Adddress1 and Address2 stay different.
two run outputs
I run that antonis executable and got on the first time:
/tmp$ ./antonis
Address1 = 7ffe2b07c148
Address2 = 7ffe2b07c148
and the second time:
/tmp$ ./antonis
Address1 = 7ffc441851a8
Address2 = 7ffc441851a8
If you want to guess why the outputs are different from one run to the next one, think of ASLR.
BTW, a very important notion when coding in C is that of undefined behavior (see also this and that answers and the references I gave there). You don't have any in your question (it is just unspecified behavior), but as my contrived answer shows, you should not expect a particular behavior in that precise case.
PS. I believe (but I am not entirely sure) that a standard conforming C implementation could output Address1= hello world and likewise for Address2. After all, the behavior of printf with %p is implementation defined. And surely you could get 0xdeadbeef for both. More seriously, an address is not always the same (of the same bitwidth) than a size_t or an int, and the standard defines intptr_t in <stdint.h>
I am learning Assembly and I am tring to understand how Assembly is being generated from C code.
I created following dummy C code:
#include <stdio.h>
int add(int x, int y){
int result = x + y;
return result;
}
int main(int argc, char *argv[]){
int x = 1 * 10;
int y = 2 * 5;
int firstArg = x + y;
int secondArg = firstArg / 2;
int value;
value = add(firstArg, secondArg);
return value;
}
And got following Assembly code
.file "first.c"
.text
.globl add
.type add, #function
add:
.LFB39:
.cfi_startproc
movl 8(%esp), %eax
addl 4(%esp), %eax
ret
.cfi_endproc
.LFE39:
.size add, .-add
.globl main
.type main, #function
main:
.LFB40:
.cfi_startproc
movl $30, %eax
ret
.cfi_endproc
.LFE40:
.size main, .-main
.ident "GCC: (Ubuntu 4.8.2-19ubuntu1) 4.8.2"
.section .note.GNU-stack,"",#progbits
And I was very surprised where are all those arithmetic operations in main vanished?
I do not understand how we got $30 from a nowhere (well, I suppose it is a return value from add function, but why I do not see any command that gets this value, actually I see that return value was already pushed to eax in the add function, so why would we need to move $30 to eax again?).
Where are all local main vars are being declared? I specially created 5 of them to see how one is pushed onto the stack.
Can you also help me to understand what are all those .LFE39 .LFB40: .LFB39: mean?
I am ready the book, but it does not clarify this case for me.
Actually book says that all function must begin with stack initialization:
pushl %ebp
movl %esp, %ebp
As well as when function ends it needs to complete it with pop instruction.
Which is not the case in the above code. I do not see any stack initialization.
Thank you!
You are compiling with optimizations enabled. GCC was smart enough to perform all of those calculations at compile-time, and replace all of that useless code with a simple constant.
First of all, x and y will get replaced with their constant expressions:
int x = 10;
int y = 10;
Then, the places where those variables are used will instead get their constant values:
int firstArg = 20;
int secondArg = 10;
Next, your add function is small and trivial, so it will certainly get inlined:
value = firstArg + secondArg;
Now those are constants too, so the whole thing will be replaced with:
int main(int argc, char *argv[]) {
return 30;
}
While most functions will have a prologue like you've shown, your program does nothing but return 30. More specifically, it no longer uses any local variables, and calls no other functions. Because of this main does not need a frame or reserved space on the call stack. So there's no need for the compiler to emit a prologue/epilogue.
main:
movl $30, %eax
ret
These are the only two instructions your program will run (other than the C-runtime startup code).
Further note, that because your add function was not marked static, the compiler had to assume that someone externally might call it. For that reason, we still see add in the generated assembly, even though no one is calling it:
add:
movl 8(%esp), %eax
addl 4(%esp), %eax
ret
Here are 2 type of code snippets which have the same outputs.
char *p = "abc";
::printf("%s",p);
And
::printf("%s","abc");
Is there any difference as to where the "abc" string is stored in memory?
I once heard that in the second code, the "abc" string is placed by the compiler in read-only memory (the .text part?)
How to tell this difference from code if any?
Many thanks.
Update
My current understanding is:
when we write:
char *p="abc"
Though this seems to be only a declarative statement, but indeed the compiler will generate many imperative instructions for it. These instructions will allocate proper space within the stack frame of the containing method, it could be like this:
subl %esp, $4
then the address of "abc" string is moved to that allocated space, it could be like this:
movl $abc_string_address, -4(%ebp)
The "abc" string is stored in the executable file image. But where in the memory it (i mean the string) will be loaded totally depends on the implementation of the compiler/linker, if it is loaded into the read-only part of the process's address space (i.e. the protection bit of the memory page is flagged as read-only), then the p is a read-only pointer, if it is loaded into the r/w part, the p is writable.
Correct me if I am wrong. Now I am looking into the assembly code generated by the gcc to have a confirmation for my understanding. I'll update this thread again shortly.
Is there any difference as to where the "abc" string is stored in memory?
Nope, and that is true for both. String literals are stored in the read-only segment. However, if you declare your variable as a char[] it will be copied onto the stack, i.e., not read only.
There is no difference in where the string literal is stored. The only difference is that the former also allocates space on the stack for the variable to store the pointer.
No difference besides a char pointer allocated on the stack for the first one.
They both use a string literal, delimited by double quotes.
Yes, it won't be stored in different locations, they are all compile-time know variables, so the compiler will generate the assembly code, and the "abc" string will be on the data segment, that is initialized data. .bss section is for unitialized data.
Try compiling with gcc and the -s option. It will generate a .s file, which is assembly code. The "abc" variable will be under the .rodata segment, same as .data for NASM assembly.
Here's the assembly code if you don't want to do the work:
This is for char* c = "abc"; printf("%s\n", c);
Note how this file has more lines of code than the other one, since this code allocates a pointer variable, and print this variable, the other solution doesn't use a variable, it justs references a static memory address.
.file "test.c"
.section .rodata
.LC0:
.string "abc"
.text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $32, %esp
movl $.LC0, 28(%esp)
movl 28(%esp), %eax
movl %eax, (%esp)
call puts
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",#progbits
And this is for printf("abc\n");
.file "test2.c"
.section .rodata
.LC0:
.string "abc"
.text
.globl main
.type main, #function
main:
pushl %ebp
movl %esp, %ebp
andl $-16, %esp
subl $16, %esp
movl $.LC0, (%esp)
call puts
movl $0, %eax
leave
ret
.size main, .-main
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",#progbits
To your edit:
I don't think any compiler would put p on a read-only memory, since you declared it as a variable on the code, it's not a hidden/protected variable generated by the compiler, it's a variable you can use whenever you want.
If you do char* p = "abc"; the compiler will sub the pointer's size to the stack, and on the later instruction, it will insert the memory address of the "abc" string (now this is put into read only) into the register, and if the compiler needs register, save it's value to the stack.
If you do printf("abc"); no variable will be alocated, since the compiler knows the string's value at compile time, so it just inserts a number there (relative to the start of the executable file) and it can read the content of that part of the memory.
In this option, you can compile it, generate a .exe, then use a HEX editor, and search for the "abc" string, and change it to "cba" or whatever (probably it will be one of the first lines or one of the last), if the compiler generates a simple .exe like this, which is probable.
In C language, Why does n++ execute faster than n=n+1?
(int n=...; n++;)
(int n=...; n=n+1;)
Our instructor asked that question in today's class. (this is not homework)
That would be true if you are working on a "stone-age" compiler...
In case of "stone-age":
++n is faster than n++ is faster than n=n+1
Machine usually have increment x as well as add const to x
In case of n++, you will have 2 memory access only (read n, inc n, write n )
In case of n=n+1, you will have 3 memory access (read n, read const, add n and const, write n)
But today's compiler will automatically convert n=n+1 to ++n, and it will do more than you may imagine!!
Also on today's out-of-order processors -despite the case of "stone-age" compiler- runtime may not be affected at all in many cases!!
Related
On GCC 4.4.3 for x86, with or without optimizations, they compile to the exact same assembly code, and thus take the same amount of time to execute. As you can see in the assembly, GCC simply converts n++ into n=n+1, then optimizes it into the one-instruction add (in the -O2).
Your instructor's suggestion that n++ is faster only applies to very old, non-optimizing compilers, which were not smart enough to select the in-place update instructions for n = n + 1. These compilers have been obsolete in the PC world for years, but may still be found for weird proprietary embedded platforms.
C code:
int n;
void nplusplus() {
n++;
}
void nplusone() {
n = n + 1;
}
Output assembly (no optimizations):
.file "test.c"
.comm n,4,4
.text
.globl nplusplus
.type nplusplus, #function
nplusplus:
pushl %ebp
movl %esp, %ebp
movl n, %eax
addl $1, %eax
movl %eax, n
popl %ebp
ret
.size nplusplus, .-nplusplus
.globl nplusone
.type nplusone, #function
nplusone:
pushl %ebp
movl %esp, %ebp
movl n, %eax
addl $1, %eax
movl %eax, n
popl %ebp
ret
.size nplusone, .-nplusone
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",#progbits
Output assembly (with -O2 optimizations):
.file "test.c"
.text
.p2align 4,,15
.globl nplusplus
.type nplusplus, #function
nplusplus:
pushl %ebp
movl %esp, %ebp
addl $1, n
popl %ebp
ret
.size nplusplus, .-nplusplus
.p2align 4,,15
.globl nplusone
.type nplusone, #function
nplusone:
pushl %ebp
movl %esp, %ebp
addl $1, n
popl %ebp
ret
.size nplusone, .-nplusone
.comm n,4,4
.ident "GCC: (Ubuntu 4.4.3-4ubuntu5) 4.4.3"
.section .note.GNU-stack,"",#progbits
The compiler will optimize n + 1 into nothingness.
Do you mean n = n + 1?
If so, they will compile to identical assembly. (Assuming that optimizations are on and that they're statements, not expressions)
Who says it does? Your compiler optimizes it all away, really, making it a moot point.
Modern compilers should be able to recognize both forms as equivalent and convert them to the format that works best on your target platform. There is one exception to this rule: variable accesses that have side effects. For example, if n is some memory-mapped hardware register, reading from it and writing to it may do more than just transferring a data value (reading might clear an interrupt, for instance). You would use the volatile keyword to let the compiler know that it needs to be careful about optimizing accesses to n, and in that case the compiler might generate different code from n++ (increment operation) and n = n + 1 (read, add, and store operations). However for normal variables, the compiler should optimize both forms to the same thing.
It doesn't really. The compiler will make changes specific to the target architecture. Micro-optimizations like this often have dubious benefits, but importantly, are certainly not worth the programmer's time.
Actually, the reason is that the operator is defined differently for post-fix than it is for pre-fix. ++n will increment "n" and return a reference to "n" while n++ will increment "n" will returning a const copy of "n". Hence, the phrase n = n + 1 will be more efficient. But I have to agree with the above posters. Good compilers should optimize away an unused return object.
In C language the side-effect of n++ expressions is by definition equivalent to the side effect of n = n + 1 expression. Since your code relies on the side-effects only, it is immediately obvious that the correct answer is that these expression always have exactly equivalent performance. (Regardless of any optimization settings in the compiler, BTW, since the issue has absolutely nothing to do with any optimizations.)
Any practical divergence in performance of these expressions is only possible if the compiler is intentionally (and maliciously!) trying to introduce that divergence. But in this case it can go either way, of course, i.e. whichever way the compiler's author wanted to skew it.
I think it's more like a hardware question rather than software... If I remember corectly, in older CPUs the n=n+1 requires two locations of memory, where the ++n is simply a microcontroller command... But I doubt this applies for modern architectures...
All those things depends on compiler/processor/compilation directives. So make any assumptions "what is faster in general" is not a good idea.