Another C vs C++ "why is doing this thing": Forward Declarations

So I got this code, and I forgot to forward declare a function but I got it compiled anyway, I can't just figure it out why! Of course if I compile in c++ I got the expected error: C3861: identifier not found.

It' 6.4 exercise on the K&R book (really exited about using a binary tree and malloc for the fist time *_* even if I used virtual alloc following hmh, I feel more by myself using only a book :) )


Here's the code HAVE FUN @_@ :
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/* binary tree for sorting and count words from a stream of text */

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>

/* #include "mylib.c" */

#define MAXWORD 100

struct tNode /* tree node */
{
    char *word;
    int count;
    struct tNode *left;
    struct tNode *right;
};

struct tNode *
AddTree(struct tNode *, char *);

void
TreePrint(struct tNode *);

/* here's the declaration I forgot */
#if 0
int
GetWord(char *, int);
#endif

int
main()
{
    struct tNode *root;
    char word[MAXWORD];

    root = NULL;
    while(GetWord(word, MAXWORD) != EOF)
        if(isalpha(word[0]))
            root = AddTree(root, word);
    TreePrint(root);
    return 0;
}



struct tNode *
TreeAlloc(void);

char *
DuplicateString(char *);

struct tNode *
AddTree(struct tNode *p, char *w)
{
    int cond;

    if(p == NULL)
    {
        p = TreeAlloc();
        p->word = DuplicateString(w);
        p->count = 1;
        p->left = p->right = NULL;
    }
    else if((cond = strcmp(w, p->word)) == 0)
    {
        p->count++;
    }
    else if(cond < 0)
    {
        p->left = AddTree(p->left, w);
    }
    else if(cond > 0)
    {
        p->right = AddTree(p->right, w);
    }
    return p;
}

void
TreePrint(struct tNode *p)
{
    if(p != NULL)
    {
        TreePrint(p->left);
        printf("%4d %s\n", p->count, p->word);
        TreePrint(p->right);
    }
}

struct tNode *
TreeAlloc(void)
{
    return(struct tNode *) malloc(sizeof(struct tNode));
}

char *
DuplicateString(char *s)
{
    char *p;

    p = (char *) malloc(strlen(s) + 1); //+1 for the string terminator obviously!
    if(p != NULL)
        strcpy(p, s);
    return p;
}

int GetWord(char *word, int lim)
{
    int c, getch(void);
    void ungetch(int);
    char *w = word;

    while(isspace(c = getch()))
        ;
    if(c != EOF)
        *w++ = c;
    if(!isalpha(c))
    {
        *w++ = '\0';
        return c;
    }
    for(;
        --lim > 0;
        w++)
        if(!isalnum(*w = getch()))
        {
            ungetch(*w);
            break;
        }
    *w = '\0';
    return word[0];
}


by the way I'm using the microsoft compiler. Microsoft (R) C/C++ Optimizing Compiler Version 19.00.23506 for x64

P.S I also needed to include the malloc.h file which is not included in the original code, otherwise I got this warnings:

w:\ansic\code\ansic.c(91): warning C4312: 'type cast': conversion from 'int' to 'tNode *' of greater size 95 on this page
w:\ansic\code\ansic.c(99): warning C4312: 'type cast': conversion from 'int' to 'char *' of greater size 103 on this page

So if anyone know what's going on...

Edited by rizoma on Reason: my english sucks
If a function is not declared before use then the compiler assumes it is declared with an int return type and vararg paramters.

Why it doesn't error when it sees a definition of that function not matching that assumption I'm not clear about.

Edited by ratchetfreak on
The C compiler doesn't do any typechecking on function calls without a declaration. The compiler assumes you know what you are doing. (If you have your warning level set high enough, it *will* warn on this. It's a good idea to do so.)

The reason this *works*, in this case, is that you're returning int, which is the assumed return type of an undeclared function. The only implication on the caller's side is how much stack to allocate for the return value. You call with the correct arguments, so they are passed properly.

Remember that "functions" are not really a machine level construct. A function call is a pointer to some other code, a place to stick the return value, and arguments placed on the stack / in registers according to a particular convention. So long as both sides of the call line up, it "Just Works". (But if you get it *wrong*, you smash the stack and your program dies. So you still want to use forward declarations.)