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
- This surprisingly successfully builds, even if I added
-Wall -Wextra -Wshadow -g
. - 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 encryptionSYNOPSIS
#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.