Skip to content

Instantly share code, notes, and snippets.

@Hritik14
Last active May 7, 2020 11:16
Show Gist options
  • Save Hritik14/13d9ca7f8150d2f5700f66e3949d2fff to your computer and use it in GitHub Desktop.
Save Hritik14/13d9ca7f8150d2f5700f66e3949d2fff to your computer and use it in GitHub Desktop.
char c = 4["ABCEDF"]
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 evaluating a[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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment