Ungrokking C

Ovid on 2003-03-09T20:36:20

I was doing a bit of C programming when I got stumped:

#include <math.h>
#include <stdio.h>

int main(void) {
  double x = 10.0, y = 3.0;
  printf("%f\n", pow(x, y));
  return (0);
}

I couldn't compile that with gcc because I kept getting an undefined reference to 'pow' error. I tried explicitily declaring the function signature before main(), but that also failed. A bit of research revealed that gcc requires I explicitly link the math library when I compile a program (by passing -lm as an argument.)

That seems odd. If I explicitly link the math library, why do I need an #include <math.h> statement in my program? It turns out that I don't.

#include <stdio.h>

double pow(double x, double y);

int main(void) {
  double x = 10.0, y = 3.0;
  printf("%f\n", pow(x, y));
  return (0);
}

I can then compile that code with

gcc -Wall testpow.c -o testpow -lm

The above code worked fine, but it seems to me that a program should contain all of the necessary elements to get it to run. Having to push some of this out to the compiler seems wrong. I suspect that I've been programming Perl for so long that working with other languages is simply a foreign experience now. This is Not Good.

Update: I discovered, after a bit of research, that many people are complaining about this. What appear to be standard C programs typed directly from book examples are mysteriously failing. Since I am using gcc 3.2, a relatively recent compiler, I'm totally confused as to the thought process here. C, while being relatively simple, still has a higher barrier to entry than many other languages. Designing a compiler that further raises this barrier seems foolish.


It's actually not that bad

Simon on 2003-03-09T20:57:00

I couldn't compile that with gcc because I kept getting an undefined reference to 'pow' error.

That's right - the pow function is not provided by the C language. If you need to use functionality provided by the language, you have to add in libraries. Just like in Perl.

I tried explicitily declaring the function signature before main(), but that also failed.

As it should; a function prototype doesn't actually contain any code to implement a function, it just allows you to use that function in your code without the compiler screaming. Just like in Perl.

A bit of research revealed that gcc requires I explicitly link the math library when I compile a program (by passing -lm as an argument.)

Only when you're using functions provided by the math library; when you're not using functions from a given library, you don't need to link in that library. Just like in Perl.

That seems odd. If I explicitly link the math library, why do I need an #include <math.h> statement in my program? It turns out that I don't.
double pow(double x, double y);

All the #include <math.h> does is give you a handy collection of prototypes; it doesn't provide any code. Since you've provided your own prototype, you don't need it.

I can then compile that code with gcc -Wall testpow.c -o testpow -lm The above code worked fine, but it seems to me that a program should contain all of the necessary elements to get it to run.

Well, no. You can try to use stuff from a library, but if you don't make that library available, your code isn't going to work. Just like in Perl.

I suspect that I've been programming Perl for so long that working with other languages is simply a foreign experience now.

Well, as I've mentioned, this is all just like Perl...

Update: I discovered, after a bit of research, that many people are complaining about this. What appear to be standard C programs typed directly from book examples are mysteriously failing.

Well, there are a lot of books about the language which are badly written. Just like Perl...

Re:It's actually not that bad

Ovid on 2003-03-09T21:36:10

Thank you very much! That does clear things up. My C, as should be readily apparent, is terribly rusty.

The compilation isn't failing; it's the linking

md5 on 2003-03-11T15:26:46

It isn't the compilation stage that is failing, rather the linking phase. For instance, try the following (it should work):

        gcc -c -o test.o test.c

You'll end up with a compiled object file 'test.o' from your source file 'test.c'.

Then, the following linking command will fail without the -lm:

        gcc -lm -o test test.o