Angus Angus - 2 months ago 12
C Question

printf in C doesn't occupy memory?

Does

printf
occupy memory in the stack?

printf("Hello world");


Does
"Hello world"
have a constant address?

Please help me understand.

EDIT:

Is the argument we are passing for the
printf
is stored in a local pointer variable.
If I use an array to store a 50 string literals it takes stack memory but if Ii use the
printf
it doesn't take memory - is what i heard. But I don't know how
printf
doesn't take memory as the array we declared.

Please help me understand!

Answer

It depends on your platform's calling convention and how the standard library is implemented.

For example, take the following program:

#include <stdio.h>

int main(void)
{
  printf("Hello, World\n");
  return 0;
}

and the following command line to compile it:

gcc -S -std=c99 -pedantic -Wall -Werror syscall.c

On a 32-bit Red Hat box (i686) using gcc 2.96, we get the following machine code:

      1         .file   "syscall.c"
      2         .version        "01.01"
      3 gcc2_compiled.:
      4                 .section        .rodata
      5 .LC0:
      6         .string "Hello, World\n"
      7 .text
      8         .align 4
      9 .globl main
     10         .type    main,@function
     11 main:
     12         pushl   %ebp
     13         movl    %esp, %ebp
     14         subl    $8, %esp
     15         subl    $12, %esp
     16         pushl   $.LC0
     17         call    printf
     18         addl    $16, %esp
     19         movl    $0, %eax
     20         leave
     21         ret
     22 .Lfe1:
     23         .size    main,.Lfe1-main
     24         .ident  "GCC: (GNU) 2.96 20000731 (Red Hat Linux 7.2 2.96-112.7.2)"

Line 16 pushes the address of the string literal onto the stack, and then printf is called.

Here's the same code, compiled the same way, on a 64-bit SLES 10 box (x86_64) using gcc 4.1.2:


      1         .file   "syscall.c"
      2         .section        .rodata
      3 .LC0:
      4         .string "Hello, World"
      5         .text
      6 .globl main
      7         .type   main, @function
      8 main:
      9 .LFB2:
     10         pushq   %rbp
     11 .LCFI0:
     12         movq    %rsp, %rbp
     13 .LCFI1:
     14         movl    $.LC0, %edi
     15         call    puts
     16         movl    $0, %eax
     17         leave
     18         ret
;;
;; additional content not included
;;

In this case, line 14 writes the address of the string literal to a register (%edi) instead of pushing it onto the stack. Note also that this version of gcc is smart enough to realize that since I'm passing a single argument of type char *, it can substitute a call to puts.

In either case you're creating a new stack frame when you make the call; the difference is what's in the stack frame. On the Red Hat box, it will include the address of the string literal; on the SLES 10 box, it won't.