Skip to content

Instantly share code, notes, and snippets.

Created August 27, 2016 11:24
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save anonymous/e28f73d160805ddafc912b4edd49e044 to your computer and use it in GitHub Desktop.
Save anonymous/e28f73d160805ddafc912b4edd49e044 to your computer and use it in GitHub Desktop.
I think the best way to answer this definitively without just handwaving
and talking about the C preprocessor is to actually write two small
example programs and compare the generated code from both. When I was
first learning C I did this constantly trying to understand how the
compiler worked. You don't need to understand assembly in great detail
to be able to spot differences in the output:
$ cat a.c
int main() {
char *line = "HTTP/1.0 500 Internal Server Error";
int line_len = sizeof("HTTP/1.0 500 Internal Server Error") - 1;
}
$ cat b.c
#include <string.h>
int main() {
char *line = "HTTP/1.0 500 Internal Server Error";
int line_len = strlen(line) - 1;
}
$ gcc -S a.c
$ gcc -S b.c
$ diff a.s b.s
1c1
< .file "a.c"
---
> .file "b.c"
16a17
> subq $16, %rsp
18c19,23
< movl $34, -12(%rbp)
---
> movq -8(%rbp), %rax
> movq %rax, %rdi
> call strlen
> subl $1, %eax
> movl %eax, -12(%rbp)
20c25
< popq %rbp
---
> leave
So in a.c we see "movl $34, -12(%rbp)" where the $34 is the number of characters in the string.
In b.c we end up with a runtime call to strlen() in order to find the length of the string.
It is obviously way more efficient to have the preprocessor pre-compute the length of the string
and just hardcode it like that.
Perhaps easier to see in a side-by-side diff. Look for the movl $34 on the left:
$ diff -y a.s b.s
.file "a.c" | .file "b.c"
.section .rodata .section .rodata
.align 8 .align 8
.LC0: .LC0:
.string "HTTP/1.0 500 Internal Server Error" .string "HTTP/1.0 500 Internal Server Error"
.text .text
.globl main .globl main
.type main, @function .type main, @function
main: main:
.LFB0: .LFB0:
.cfi_startproc .cfi_startproc
pushq %rbp pushq %rbp
.cfi_def_cfa_offset 16 .cfi_def_cfa_offset 16
.cfi_offset 6, -16 .cfi_offset 6, -16
movq %rsp, %rbp movq %rsp, %rbp
.cfi_def_cfa_register 6 .cfi_def_cfa_register 6
> subq $16, %rsp
movq $.LC0, -8(%rbp) movq $.LC0, -8(%rbp)
movl $34, -12(%rbp) | movq -8(%rbp), %rax
> movq %rax, %rdi
> call strlen
> subl $1, %eax
> movl %eax, -12(%rbp)
movl $0, %eax movl $0, %eax
popq %rbp | leave
.cfi_def_cfa 7, 8 .cfi_def_cfa 7, 8
ret ret
.cfi_endproc .cfi_endproc
.LFE0: .LFE0:
.size main, .-main .size main, .-main
.ident "GCC: (Debian 6.1.1-11) 6.1.1 20160802" .ident "GCC: (Debian 6.1.1-11) 6.1.1 20160802"
.section .note.GNU-stack,"",@progbits .section .note.GNU-stack,"",@progbits
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment