Page 1 of 2 12 LastLast
Results 1 to 10 of 13

Thread: change one line, get a compile error

  1. #1
    Join Date
    Aug 2009
    Beans
    101

    change one line, get a compile error

    The following program, "main_good.c",
    Code:
    #include <stdio.h>
    #include <math.h>
    
    int main ()
    {
            double p = 3.14159265;
    //        double s = sin(p/4.0);
            double s= sin(3.14159265/4.0);
            printf ("sin  is %f\n", s);
    }
    compiles under gcc without problems (and produces the correct answer).

    But the following code, "main_bad.c",
    Code:
    #include <stdio.h>
    #include <math.h>
    
    int main ()
    {
            double p = 3.14159265;
            double s = sin(p/4.0);
    //        double s= sin(3.14159265/4.0);
            printf ("sin  is %f\n", s);
    }
    Produces rhw error:
    Code:
    /tmp/cc819Wha.o: In function `main':
    main_bad.c:(.text+0x23): undefined reference to `sin'
    collect2: ld returned 1 exit status
    Following a suggestion in this thread , tried compiling with the -lm switch. Same error.

    Can anyone explian what is happening ?
    Hopefullly something simple; haven't programmed in plain old C for a long time.
    thanks for any help -

  2. #2
    Join Date
    Jul 2008
    Location
    The Left Coast of the USA
    Beans
    Hidden!
    Distro
    Kubuntu

    Re: change one line, get a compile error

    Just for giggles and grins ...

    What happens if you do something like this...

    Code:
            .
    double p = 3.14159265;
    double q = 4.0;
    double r = p/q;
    double s = sin(r);
    or

    Code:
            .
    double p = 3.14159265;
    double q = 4.0;
    double s = sin(p/q);
    (... and I'll not get into a discussion about the naming of your variables ... )
    Last edited by QIII; August 15th, 2013 at 08:15 PM.

  3. #3
    Join Date
    Apr 2012
    Beans
    6,188

    Re: change one line, get a compile error

    Where exactly are you adding the -lm? please post your exact compile command (the position of the library relative to the source file matters)

    Probably what is happening is that when you do

    Code:
    double s= sin(3.14159265/4.0);
    the compiler is optimizing it out (i.e. the compiler itself is evaluating the 'sin' function, and replacing the function call with a constant - so that no external linkage to libm is needed)

    When you do

    Code:
    double s= sin(p/4.0);
    then the compiler can't do that because the argument contains a variable (it would be interesting to see what happens if you declare p as const double).

  4. #4
    Join Date
    Jun 2007
    Location
    Maryland, US
    Beans
    6,257
    Distro
    Kubuntu

    Re: change one line, get a compile error

    Quote Originally Posted by George Heine View Post
    Following a suggestion in this thread , tried compiling with the -lm switch. Same error.
    Really?? Please show how you compiled the program, for I have my doubts.

  5. #5

    Re: change one line, get a compile error

    I defer to steeldriver's explanation.

    The reason people are asking about the command line you used to compile it is because compilers can be notoriously finicky about the order of arguments, especially when it comes to linking.

    Code:
    $ cc -lm foo.c  # may not work depending on what cc is
    $ cc foo.c -lm  # the "correct" way
    Me, I can never remember which order things are supposed to go in, especially when you throw a "-o foo" in the mix, so I like to rely on make to remember it for me:
    Code:
    $ LDLIBS="-lm" make foo
    This has the added advantage of also recognizing the CFLAGS variable, which I define in my .zshrc as below (you'll also notice I use clang instead of gcc):
    Code:
    $ export CFLAGS="-std=c11 -Wall -Wextra -pedantic -Wwrite-strings"
    $ export LDLIBS="-lm"
    $ make foo
    clang -std=c11 -Wall -Wextra -pedantic -Wwrite-strings    foo.c  -lm -o foo
    Obviously when you go beyond simple programs it's time to write a real Makefile, but this saves me typing on a regular basis, because I never compile anything without lots of warnings enabled. It's a good habit to be in.

  6. #6
    Join Date
    Aug 2011
    Location
    47°9′S 126°43W
    Beans
    2,160
    Distro
    Kubuntu 14.04 Trusty Tahr

    Re: change one line, get a compile error

    Incidentally, math.h defines:
    Code:
    # define M_PI        3.14159265358979323846    /* pi */
    # define M_PI_2        1.57079632679489661923    /* pi/2 */
    # define M_PI_4        0.78539816339744830962    /* pi/4 */
    (and also the long forms)

  7. #7
    Join Date
    Aug 2009
    Beans
    101

    Re: change one line, get a compile error

    Thanks for all the informative responses.

    Following suggestions from trent.josephsen and dwhitney67, tried recompiling with
    Code:
    gcc main_bad.c -lm
    And it works, with no problems. So apparently the order of the flags was the issue.
    Will experiment with suggestions of trent.josephsen's for using "make" rather than calling gcc directly.

    Thanks also to Steeldriver for some insights on why the problem occurred in the first place.
    I will try the suggestions of QIII on some different methods of declaration, and report back if
    anything interesting turns up.

    Of course, the real goal is to understand what is going on. Can anyone recommend
    a good source of information (other than the voluminous man pages) that could help
    with figuring out the gcc command-line syntax?

  8. #8

    Re: change one line, get a compile error

    Quote Originally Posted by George Heine View Post
    Of course, the real goal is to understand what is going on. Can anyone recommend
    a good source of information (other than the voluminous man pages) that could help
    with figuring out the gcc command-line syntax?
    Nope. Sorry.

    I believe the special case regarding placement of -lfoo predates gcc, and it has something to do with the order in which symbols are made available for linkage, but if it makes sense to anybody, that somebody is not me. AFAIK the man pages are your only real recourse. Yes, the man page for gcc is over 17,000 lines long, but you can search it, so it's usually not too hard to find something you're looking for. I don't know of any other reliable resource that goes beyond "gcc -o bar bar.c -lfoo" in complexity.

  9. #9
    Join Date
    Apr 2012
    Beans
    6,188

    Re: change one line, get a compile error

    I've been meaning to follow up on why libm is not required (and therefore why the placement of the -lm doesn't matter) when you change the line to a constant expression that can be evaluated at compile time

    You can kind of see how this happens if you use the -S option to stop compilation at the assembler stage, and then look for what function calls are present the assembly file. So for example if we have the original non-constant version:

    Code:
    $ cat sin1.c
    #include <stdio.h>
    #include <math.h>
    
    int main()
    {
      double p = 3.1415926;
      double v;
    
      v = sin(p/4.0);
      printf("%lf\n", v);
    
      return 0;
    }
    then

    Code:
     
    $ gcc -S sin1.c
    $ 
    $ grep 'call' sin1.s
        call    sin
        call    printf
    $
    but if we replace the sin argument by a constant expression:

    Code:
    $ cat sin2.c
    #include <stdio.h>
    #include <math.h>
    
    int main()
    {
      double p = 3.1415926;
      double v;
    
      v = sin(3.1415926/4.0);
      printf("%lf\n", v);
    
      return 0;
    }
    then

    Code:
    $ gcc -S sin2.c
    $ 
    $ grep 'call' sin2.s
        call    printf
    $
    Hope this helps

  10. #10
    Join Date
    Nov 2005
    Location
    Bordeaux, France
    Beans
    11,294
    Distro
    Ubuntu 12.04 Precise Pangolin

    Re: change one line, get a compile error

    Quote Originally Posted by George Heine View Post
    Of course, the real goal is to understand what is going on. Can anyone recommend
    a good source of information (other than the voluminous man pages) that could help
    with figuring out the gcc command-line syntax?
    For this particular issue only. I am by no means an expert on compilers, but here is (my understanding of) what's happening. The first thing to remember is that the source files and libraries are processed in the order they appear onthe command like.

    Good: gcc -o foo foo.c -lm

    What happens is that the compiler first processes the file foo.c. It sees that there is a call to the sin() function. Since the code of the function is not provided in the file, the compiler will make some kind of internal note that the code of the function sin() is needed, and to get it from a subsequent file or library that provides it.

    Bad: gcc -o foo -lm foo.c

    Based on the above it's easy to guess what happens. First the compiler processes the libm library. Since there is no pending memo that the code of some function is needed, it will conclude that the library is not needed and carry on. The reason this syntax works on some (most?) systems is that when the compiler processes a library, it will keep track of all the functions that this library provides, in case a subsequent file needs it. Aside from the obvious drawback of having to keep all those memos around (especially if there is a lot of libraries in use), I do not know of any other reason to prefer the "new" behavior (but then again, I am not an expert).
    「明後日の夕方には帰ってるからね。」


Page 1 of 2 12 LastLast

Bookmarks

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •