- Published on
My notes on C language
#include <stdio.h>
int main(void) {
int charValue = 'A';
int multiChar = 'AB';
const char *stringValue = "ABC";
printf("Single char constant (int): %d\n", charValue);
printf("Multi-char constant (int): %d\n", multiChar);
printf("String literal (const char *): %s\n", stringValue);
return 0;
}
why 'AB'
evaluates to 16706
Packing (Little-Endian):
'AB' = 0x42 (B) 0x41 (A)
= 0x4241 (Hexadecimal)
= 16961 (Decimal)
'AB' = 0x41 (A) 0x42 (B)
= 0x4142 (Hexadecimal)
= 16706 (Decimal)
hex(ord('A')), hex(ord('B')) # 'A' = 0x41, 'B' = 0x42
int('0x4142', 16) # 16706
String Literal:
"A"
is a string (typeconst char *
), which points to the memory address ofA
and a null terminator (\0
).
in c99 standard section 5.1.2
- All objects with static storage duration shall be initialized (set to their initial values) before program startup
{
static int a;
++a;
printf("%d\n", a);
}
prints 1 2 ...
if you remove static then you might get garbage values but wait try to run it
void fun(void) {
int a;
++a;
printf("%d\n", a);
}
int main(void) {
fun();
for (int i = 0; i < 20; ++i) {
fun();
}
}
you dont get garbage anymore
why?
on binary without for loop run this
objdump -M intel -d binary
; this is assemnly without for loop
0000000000001139 <fun>:
1139: 55 push rbp
113a: 48 89 e5 mov rbp,rsp
113d: 48 83 ec 10 sub rsp,0x10
1141: 83 45 fc 01 add DWORD PTR [rbp-0x4],0x1
1145: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
1148: 89 c6 mov esi,eax
114a: 48 8d 05 b3 0e 00 00 lea rax,[rip+0xeb3] # 2004 <_IO_stdin_used+0x4>
1151: 48 89 c7 mov rdi,rax
1154: b8 00 00 00 00 mov eax,0x0
1159: e8 d2 fe ff ff call 1030 <printf@plt>
115e: 90 nop
115f: c9 leave
1160: c3 ret
0000000000001161 <main>:
1161: 55 push rbp
1162: 48 89 e5 mov rbp,rsp
1165: e8 cf ff ff ff call 1139 <fun>
116a: b8 00 00 00 00 mov eax,0x0
116f: 5d pop rbp
1170: c3 ret
look closely at line 1145 the stuff at [rbp-0x4] is to what is printed but we dont see any initialization of that in main function , dont believe me run it yourself with nasm.
section .text
extern printf
global _start
_start:
call fun
call fun
call fun
mov rax, 60
xor rdi, rdi
syscall
fun:
push rbp
mov rbp, rsp
sub rsp, 0x10
add dword [rbp-0x4], 0x1
mov eax, dword [rbp-0x4]
mov esi, eax
lea rdi, [fmt]
mov eax,0x0
call printf
nop
leave
ret
section .data
fmt: db "%d", 10, 0
now we will see assembly with for loop, well can you see line 1178 and this is initialized to 0 properly , currently i have no idea what the .. is going on here in generating assembly why compiler is getting it right initialization on this chance , whatever is this a compiler bug? i mean if you want to be wrong then be in both case dont give me false hopes, may be we shoudl try looking at clang and gcc source code
0000000000001139 <fun>:
1139: 55 push rbp
113a: 48 89 e5 mov rbp,rsp
113d: 48 83 ec 10 sub rsp,0x10
1141: 83 45 fc 01 add DWORD PTR [rbp-0x4],0x1
1145: 8b 45 fc mov eax,DWORD PTR [rbp-0x4]
1148: 89 c6 mov esi,eax
114a: 48 8d 05 b3 0e 00 00 lea rax,[rip+0xeb3] # 2004 <_IO_stdin_used+0x4>
1151: 48 89 c7 mov rdi,rax
1154: b8 00 00 00 00 mov eax,0x0
1159: e8 d2 fe ff ff call 1030 <printf@plt>
115e: 90 nop
115f: c9 leave
1160: c3 ret
0000000000001161 <main>:
1161: 55 push rbp
1162: 48 89 e5 mov rbp,rsp
1165: 48 83 ec 10 sub rsp,0x10
1169: e8 cb ff ff ff call 1139 <fun>
116e: e8 c6 ff ff ff call 1139 <fun>
1173: e8 c1 ff ff ff call 1139 <fun>
1178: c7 45 fc 00 00 00 00 mov DWORD PTR [rbp-0x4],0x0
117f: eb 09 jmp 118a <main+0x29>
1181: e8 b3 ff ff ff call 1139 <fun>
1186: 83 45 fc 01 add DWORD PTR [rbp-0x4],0x1
118a: 83 7d fc 13 cmp DWORD PTR [rbp-0x4],0x13
118e: 7e f1 jle 1181 <main+0x20>
1190: b8 00 00 00 00 mov eax,0x0
1195: c9 leave
1196: c3 ret