Home > Enterprise >  No output from split up source, but no warnings either, when omitting an included file
No output from split up source, but no warnings either, when omitting an included file

Time:08-14

I ran into an issue invoking gcc where if I omit a library .c file, I got no output from the binary (unexpected behavior change) but since this is a missing dependency, I kind of expected the compile to fail (or at least warn)...

Example for this issue is from Head First C page 185 (but is not errata, see my compile mis-step below):

encrypt.h:

void encrypt(char *message);

encrypt.c:

#include "encrypt.h"

void encrypt(char *message)
{
    // char c; errata
    while (*message) {
        *message = *message ^ 31;
        message  ;
    }
}

message_hider.c:

#include <stdio.h>
#include "encrypt.h"

int main() {
    char msg[80];
    while (fgets(msg, 80, stdin)) {
        encrypt(msg);
        printf("%s", msg);
    }
}

NOW, everything works fine IF I faithfully compile as per exercise instruction:

gcc message_hider.c encrypt.c -o message_hider

... but bad fortune led me to compile only the main .c file, like so:

$ gcc message_hider.c -o message_hider
  1. This surprisingly successfully builds, even if I added -Wall -Wextra -Wshadow -g.
  2. Also surprisingly, it silently fails, with no output from encrypt() function:
$ ./message_hider < ./encrypt.h 
$ 

my gcc is:

$ /usr/bin/gcc --version
Apple clang version 13.1.6 (clang-1316.0.21.2.5)
Target: x86_64-apple-darwin21.6.0
Thread model: posix
InstalledDir: /Library/Developer/CommandLineTools/usr/bin

Mindful that even with a Makefile, I could "still" end up with a missing .c file due to a mistake in the recipe.

Q: Is it possible to force a hard error if I forget to tell gcc about a .c file?

CodePudding user response:

As I noted in a (misspelled) comment:

There is probably a function encrypt() in the system library.

On a Mac, man -s 3 encrypt shows:

CRYPT(3) BSD Library Functions Manual CRYPT(3)

NAME
crypt, encrypt, setkey -- DES encryption

SYNOPSIS

#include <unistd.h>

char *
crypt(const char *key, const char *salt);

void
encrypt(char *block, int edflag);

#include <stdlib.h>

void
setkey(const char *key);

The encrypt() and setkey() functions are part of POSIX, so they'll be available on most POSIX-like systems. Curiously, as shown in the manual page extract, the functions are declared in separate headers — <unistd.h> for encrypt() and <stdlib.h> for setkey(). There's probably a good (enough) historical reason for the disconnect.

You should have received a compiler warning about the function being undeclared — if you didn't, you are presumably compiling using the C90 standard. That is very old and should not still be being taught; you need to be learning C11 or C18 (almost the same).

Since C99, the C standard requires functions to be declared before use — you can define a static function without pre-declaring it, but all other functions (except main()) should be declared before they are used or defined. You can use GCC compiler warning options such as -Wmissing-prototypes -Wstrict-prototypes (along with -Wold-style-declaration and -Wold-style-definition) to trigger warnings. Of these, -Wold-style-declaration is enabled by -Wextra (and none by -Wall). Be aware: as noted in the comments, clang does not support -Wold-style-declaration though true GCC (not Apple's clang masquerading as gcc) does support it.

  • Related