pow function working unexpectedly

Giorgos Keramidas keramida at ceid.upatras.gr
Wed Apr 12 11:05:10 UTC 2006


On 2006-04-11 22:54, Jonathan Herriott <herriojr at gmail.com> wrote:
> I just want to make sure I'm not being stupid before I send in a bug.
> The problem seems to be with gcc when using the pow function in the
> math.h library.  Here's code that works:
>
> #include <stdio.h>
> #include <math.h>
>
> int main()
> {
>      printf("%f\n", pow(2,3));
>      return 0;
> }
>
>
> Now, the following will not compile:
>
> #include <stdio.h>
> #include <math.h>
>
> int main()
> {
>      int x = 2; // I tried these as doubles too since the pow function
> takes doubles
>      int y = 3;
>
>      printf("%f\n", pow(x,y));
>      return 0;
> }
>
> I compiled both programs using:
> gcc test.c
>
> The second example gives the following error:
> /var/tmp//ccxtkMwv.o(.text+0x45): In function `main':
> : undefined reference to `pow'

There are two things at work here that are a bit confusing.  In the
first case, the arguments of pow() are constants, so the compiler knows
the result of the pow() call at compile-time.  GCC tries to optimize
this call away by replacing the entire pow() call with the literal
result.  You can see this by:

# $ cat -n pow1.c
#      1  #include <stdio.h>
#      2  #include <math.h>
#      3
#      4  int
#      5  main(void)
#      6  {
#      7
#      8          printf("%f\n", pow(2,3));
#      9          return 0;
#     10  }

If you compile this program to assembler, there is no call to pow():

# $ gcc -std=c99 -pedantic -O2 -S pow1.c
# $ cat -n pow1.s
#      1          .file   "pow1.c"
#      2          .section        .rodata.str1.1,"aMS", at progbits,1
#      3  .LC1:
#      4          .string "%f\n"
#      5          .text
#      6          .p2align 2,,3
#      7  .globl main
#      8          .type   main, @function
#      9  main:
#     10          pushl   %ebp
#     11          movl    %esp, %ebp
#     12          subl    $8, %esp
#     13          andl    $-16, %esp
#     14          subl    $20, %esp
#     15          pushl   $1075838976
#     16          pushl   $0
#     17          pushl   $.LC1
#     18          call    printf
#     19          xorl    %eax, %eax
#     20          leave
#     21          ret
#     22          .size   main, .-main
#     23          .ident  "GCC: (GNU) 3.4.4 [FreeBSD] 20050518"
# $

Lines 15-17 are pushing the arguments of printf() on the stack, so
obviously GCC has pre-calculated the value of pow(2,3) for us.

With the second program, which uses variables for storing the values
passed to pow(), GCC cannot use the same trick, as the *values* of the
variables are only known at runtime.  This way, this program:

# $ cat -n pow2.c
#      1  #include <stdio.h>
#      2  #include <math.h>
#      3
#      4  int
#      5  main(void)
#      6  {
#      7          int x = 2; /* I tried these as doubles too since the pow function takes doubles */
#      8          int y = 3;
#      9
#     10          printf("%f\n", pow(x,y));
#     11          return 0;
#     12  }
# $

Compiles to slightly different object code:

# $ gcc -std=c99 -pedantic -O2 -S pow2.c
# $ cat -n pow2.s
#      1          .file   "pow2.c"
#      2          .section        .rodata.str1.1,"aMS", at progbits,1
#      3  .LC0:
#      4          .string "%f\n"
#      5          .text
#      6          .p2align 2,,3
#      7  .globl main
#      8          .type   main, @function
#      9  main:
#     10          pushl   %ebp
#     11          movl    %esp, %ebp
#     12          subl    $8, %esp
#     13          andl    $-16, %esp
#     14          subl    $32, %esp
#     15          pushl   $1074266112
#     16          pushl   $0
#     17          pushl   $1073741824
#     18          pushl   $0
#     19          call    pow
#     20          addl    $20, %esp
#     21          fstpl   (%esp)
#     22          pushl   $.LC0
#     23          call    printf
#     24          xorl    %eax, %eax
#     25          leave
#     26          ret
#     27          .size   main, .-main
#     28          .ident  "GCC: (GNU) 3.4.4 [FreeBSD] 20050518"

Here a call to pow() is used, so the second program uncovers the fact
that you need the -lm math library to work with math functions, which is
why GCC complains about an undefined reference to pow().

> If I comile with g++, I have no issues.  Are these results that I
> should have?  If so, why?  If not, I'm going to submit the bug on gcc
> (or the linker, but I'm guessing it's the same group).

This is not a C++ program, so you should use a C compiler for it :)

Regards,
Giorgos



More information about the freebsd-questions mailing list