OhNo_Segfault
OhNo_Segfault

Reputation: 153

Compiled C program with call to undefined/undeclared function; no error or warning reported. Why?

I'm copying an example from Kernighan & Ritchie's "C Programming Language (2nd Edition)". Just to make sure I had copied the code correctly (and to test its functionality), I compiled this code:

/*This is an example program from chapter 5, section 6 (Pointer Arrays; Pointers to Pointers)*/
#include <stdio.h>
#include <string.h>
#include "/home/alecto/Compsci/Cprogramming/Utils/get_line.c"
#include "/home/alecto/Compsci/Cprogramming/Kernighan_Ritchie_5/alloc.c"

#define MAXLINES 5000 /*max number of lines to be sorted*/

char *lineptr[MAXLINES]; /*pointers to lines of text*/

int readlines(char *lineptr[], int nlines);
void writelines(char *lineptr[], int nlines);
void qsort(char *lineptr[], int left, int right);

/* sort input lines */
main()
{
  int nlines; /* number of input lines read */

  if ((nlines = readlines(lineptr, MAXLINES)) >= 0) {
    qsort(lineptr, 0, nlines-1);
    writelines(lineptr, nlines);
    return 0;
  }
  else {
    printf("error: input too big for sort\n");
    return 1;
  }
}
... //readlines() and writelines() are defined in my source file, but not
... //qsort()

The program compiles with no complaints from gcc or the linker, despite the lack of a definition for qsort() in the source file. I tried commenting out the declaration void qsort(char *lineptr[], int left, int right); while leaving the call to qsort() active in main() just to see if I could induce an error, but the program still manages to compile and run silently, without complaint or unexpected behaviour

What's going on here?

Upvotes: 3

Views: 2626

Answers (3)

Keith Thompson
Keith Thompson

Reputation: 263267

qsort is a standard library function, declared in <stdlib.h>.

The compiler needs a visible declaration of qsort, and you've provided such a declaration in your source file.

The linker needs a definition of qsort; that's provided by the standard C library. That function is incompatible with your declaration, but that's not an error that linkers typically can detect.

Because you've declared a standard library function in a manner that's incompatible with the actual function, your program has undefined behavior.

As for why your program still compiles when you remove your declaration of qsort, that's because it's following an old version of the C standard. As of the C90 standard, it's legal to call a function with no visible declaration; the compiler assumes that the function returns an int. C99 dropped the "implicit int" rule, requiring a compile-time diagnostic for such a call -- but gcc still follows the C90 standard (with gcc-specific extensions) by default. Use -std=c99 or -std=c11 to ask gcc to conform to a more modern edition of the C standard; add -pedantic -Wall -Wextra to get more warnings.

That's how to get the compiler to diagnose your error (trying to redeclare qsort). To fix that error, you need to use a name other than qsort and you need to provide a valid declaration and definition.

Also, it rarely makes sense to have a #include directive for a .c files. Normally .c files (which provide definitions) are compiled separately, and .h files (which provide declarations) are #included. That's a convention, not a language rule, but following it makes organizing your code much easier. There's more to know about how to do this (header guards, how to link multiple objects into a single program, etc.), but that's beyond the scope of this question.

Upvotes: 3

OhNo_Segfault
OhNo_Segfault

Reputation: 153

qsort() is included in <stdlib.h>; so even though the arguments in my calls to this function shouldn't make any sense to the compiler, referencing qsort() after including it via the library seems to be perfectly legal.

@mfro if you'll post an answer saying something to this effect, I'll give you credit for the answer.

Upvotes: 1

Some programmer dude
Some programmer dude

Reputation: 409176

The thing is that you are not including header files, you are including the complete source files, creating a single translation unit. Since the functions are both declared and defined in those included files, you get no error because the compiler have the declarations.

If you separated the compilation, and compiled each source file separately (and removed those include directives) then you would get if not errors at least warnings.

Upvotes: 1

Related Questions