weird.c
--------------
#include<stdio.h>
int main(){
int i = 4;
char c = i["ABCDEF"];
printf("%c", c);
return 0;
}
Output: E
i
isn't an array, and "ABCDEF"
isn't an index. Let's explore the mystery Obi Wan.
In the holy book of K&R in section 5.3 it is clearly mentioned that
Rather more surprising, at least at first sight, is the fact that a reference to
a[i]
can also be written as*(a+i)
In evaluatinga[i]
, C converts it to*(a+i)
immediately; the two forms are completely equivalent.
Which implies i["ABCDEF"]
is converted to *(i + "ABCDEF")
which is just i-th index of the char[] literal "ABCDEF" : E
Mystry solved !
Not yet satisfied ? Let's write another program
weird2.c
----------------
#include<stdio.h>
int main(){
int i = 4;
char c = *(i + "ABCDEF");
printf("%c", c);
return 0;
}
and generate the ASM for both of them using
gcc -S -masm=intel -fomit-frame-pointer -O0 weird.c
gcc -S -masm=intel -fomit-frame-pointer -O0 weird2.c
ASM files
weird.s
-----------
.file "weird.c"
.intel_syntax noprefix
.text
.section .rodata
.LC0:
.string "ABCDEF"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
sub rsp, 24
.cfi_def_cfa_offset 32
mov DWORD PTR 12[rsp], 4
mov eax, DWORD PTR 12[rsp]
cdqe
lea rdx, .LC0[rip]
movzx eax, BYTE PTR [rax+rdx]
mov BYTE PTR 11[rsp], al
movsx eax, BYTE PTR 11[rsp]
mov edi, eax
call putchar@PLT
mov eax, 0
add rsp, 24
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Arch Linux 9.3.0-1) 9.3.0"
.section .note.GNU-stack,"",@progbits
weird2.s
----------
.file "weird2.c"
.intel_syntax noprefix
.text
.section .rodata
.LC0:
.string "ABCDEF"
.text
.globl main
.type main, @function
main:
.LFB0:
.cfi_startproc
sub rsp, 24
.cfi_def_cfa_offset 32
mov DWORD PTR 12[rsp], 4
mov eax, DWORD PTR 12[rsp]
cdqe
lea rdx, .LC0[rip]
add rax, rdx
movzx eax, BYTE PTR [rax]
mov BYTE PTR 11[rsp], al
movsx eax, BYTE PTR 11[rsp]
mov edi, eax
call putchar@PLT
mov eax, 0
add rsp, 24
.cfi_def_cfa_offset 8
ret
.cfi_endproc
.LFE0:
.size main, .-main
.ident "GCC: (Arch Linux 9.3.0-1) 9.3.0"
.section .note.GNU-stack,"",@progbits
and diff
the generated weird.s and weird2.s
files:
❯ diff weird.s weird2.s
1c1
< .file "weird.c"
---
> .file "weird2.c"
19c19,20
< movzx eax, BYTE PTR [rax+rdx]
---
> add rax, rdx
> movzx eax, BYTE PTR [rax]
Clearly, the change is absolutely nothing. Implying, both weird files are equivalent to the language thus aren't really weird at all.
SOLVED !
PS: Replace i
with 4 and the title would make sense as well.