#1
  1. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    142
    Rep Power
    2

    Forgetting function prototypess


    sometimes when I enter a definition of a function but forget the prototype, the compiler doesn't return an error, and the .exe window opens up as if there was nothing wrong.

    it seems that this happens with functions with no return value.

    why does this happen?
  2. #2
  3. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,174
    Rep Power
    2222
    What do the warnings say?

    Even if you get warnings, the compiler will generate an exe file. But you're a fool if you try to run it, because those warnings are telling you that there's something wrong with your code.

    Originally Posted by 046
    it seems that this happens with functions with no return value.
    Please provide us with a few short examples, short complete programs that illustrate the problem.
  4. #3
  5. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    142
    Rep Power
    2
    here's the program:
    Code:
    int main()
    {
        double x1[] = {1.5,2.2, 3.4, 5.1, 6.7};
        double x2[] = {2.0, 4.5, 1.3, 4.0, 5.5};
        double sum[SIZE];
        int n;
        int ct;
        n = 5;
        add_arrays(&x1[0], &x2[0], &sum[0], n);
    
        for(ct = 0; ct < n; ++ct)
            printf("%.2f\n", sum[ct]);
    }
    
    void add_arrays(const double x1[], const double x2[], double sum[], int n)
    {
        int ct;
        for(ct = 0; ct < n; ++ct)
            sum[ct] = x1[ct] + x2[ct];
    }
    edit
    sorry, I posted the wrong program.
    also, I came up with a hypothesis.
    what happened was that I ran the program once WITH the prototype, and then ran the program WITHOUT the prototype, and got the expected result.
    in the second run, I didn't change anything except deleting the prototype.
    could it be that that because of the first run of the program, the memory cells retained the data from that run instead of garbage, and since I didn't change the numbers being added in the second run, what I got "seemed" correct?
  6. #4
  7. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,174
    Rep Power
    2222
    What do the warnings say?
    C:>gcc -Wall implicit1.c
    implicit1.c: In function `main':
    implicit1.c:3: `MAX_SIZE' undeclared (first use in this function)
    implicit1.c:3: (Each undeclared identifier is reported only once
    implicit1.c:3: for each function it appears in.)
    implicit1.c:7: warning: implicit declaration of function `fill_sentinel'
    implicit1.c:10: warning: implicit declaration of function `printf'
    implicit1.c:3: warning: unused variable `x'
    implicit1.c:12: warning: control reaches end of non-void function
    implicit1.c: At top level:
    implicit1.c:16: warning: type mismatch with previous implicit declaration
    implicit1.c:7: warning: previous implicit declaration of `fill_sentinel'
    implicit1.c:16: warning: `fill_sentinel' was previously implicitly declared to return `int'
    implicit1.c: In function `fill_sentinel':
    implicit1.c:21: warning: implicit declaration of function `scanf'

    C:>
    Notice all those "implicit declaration of function" warnings? That's what happens when there's no prototype for that function. Since a lot of those warnings are from your having left out the #include for stdio.h, I tried to clean things up by adding that in along with the #define for MAX_SIZE, and now we get mostly the warnings of interest for this problem:
    C:>gcc -Wall implicit1.c
    implicit1.c: In function `main':
    implicit1.c:11: warning: implicit declaration of function `fill_sentinel'
    implicit1.c:16: warning: control reaches end of non-void function
    implicit1.c: At top level:
    implicit1.c:20: warning: type mismatch with previous implicit declaration
    implicit1.c:11: warning: previous implicit declaration of `fill_sentinel'
    implicit1.c:20: warning: `fill_sentinel' was previously implicitly declared to return `int'

    C:>
    Examining each warning in the order of appearance:

    implicit1.c:11: warning: implicit declaration of function `fill_sentinel'
    This is the warning that there you are calling a function that hasn't been defined yet (eg, the prototype is missing), so the compiler has to guess at what it could possibly be; that's what an implicit declaration is. It is a very bad idea to make the compiler guess what it is that you want it to do, because you almost never get what you want.

    implicit1.c:16: warning: control reaches end of non-void function
    You need to return a value from main, such as zero for success. If you make a promise, then you need to keep that promise.

    implicit1.c:20: warning: type mismatch with previous implicit declaration
    The compiler has just found the actual definition of the function and reality does not match the assumptions that you had forced it to make about the function. Since it had already defined that function based on its guesses, it has no choice but to reject this "redefinition" that you just threw at it. The compiler's fantasies about the function take precedence over the reality of what you wanted. That means that the program will not be doing what you want it to do, which is why you should never run a program that's giving you warnings.

    implicit1.c:11: warning: previous implicit declaration of `fill_sentinel'
    This is a follow-up to the previous warning to tell you where it had performed that implicit declaration.

    implicit1.c:20: warning: `fill_sentinel' was previously implicitly declared to return `int'
    In the compiler's fantasies, this function is supposed to return an int value. Again, it is ignoring the reality of what you actually wanted.


    I thought you said that that compiled with no problems. That certainly is not the case.
  8. #5
  9. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,174
    Rep Power
    2222
    Again correcting for the really stupid mistakes, this is what I'm compiling:
    Code:
    #include <stdio.h>
    
    #define SIZE  42
    
    int main()
    {
        double x1[] = {1.5,2.2, 3.4, 5.1, 6.7};
        double x2[] = {2.0, 4.5, 1.3, 4.0, 5.5};
        double sum[SIZE];
        int n;
        int ct;
        n = 5;
        add_arrays(&x1[0], &x2[0], &sum[0], n);
    
        for(ct = 0; ct < n; ++ct)
            printf("%.2f\n", sum[ct]);
    
        return 0;
    }
    
    void add_arrays(const double x1[], const double x2[], double sum[], int n)
    {
        int ct;
        for(ct = 0; ct < n; ++ct)
            sum[ct] = x1[ct] + x2[ct];
    }
    Here is the compiler's output:
    C:>gcc -Wall implicit2.c
    implicit2.c: In function `main':
    implicit2.c:13: warning: implicit declaration of function `add_arrays'
    implicit2.c: At top level:
    implicit2.c:22: warning: type mismatch with previous implicit declaration
    implicit2.c:13: warning: previous implicit declaration of `add_arrays'
    implicit2.c:22: warning: `add_arrays' was previously implicitly declared to return `int'
    C:>
    Still the same problems as described above.

    Do you even have warnings turned on?

    I'm using MinGW gcc. What compiler are you using?

    PS
    Instead of writing this,
    add_arrays(&x1[0], &x2[0], &sum[0], n);
    , why don't you instead write this,
    add_arrays(x1, x2, sum, n);
    ?

    The second way is the common way that everybody uses. The first way is unusual and would make another program stop and wonder what you're trying to do, thinking that you're attempting something fancy.
    Last edited by dwise1_aol; June 26th, 2013 at 06:00 PM.
  10. #6
  11. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    142
    Rep Power
    2
    my compiler is also MinGW Compiler, version 4.7.1.

    I checked my log, and I did see warnings.
    C:\Programming\Files\tester1.c|18|warning: conflicting types for 'add_arrays' [enabled by default]|
    C:\Programming\Files\tester1.c|12|note: previous implicit declaration of 'add_arrays' was here|
    ||=== Build finished: 0 errors, 1 warnings (0 minutes, 0 seconds) ===|
    I said "it ran without problems" because I had assumed that if a program didn't go into infinite loops, a popup window didn't show up telling me an error had occurred, and I got the correct results, the program had no problems.
    so I didn't check my logs, and said it didn't have any errors.
    I apologize for my imprecise language.
  12. #7
  13. Contributing User
    Devshed Supreme Being (6500+ posts)

    Join Date
    Jan 2003
    Location
    USA
    Posts
    7,174
    Rep Power
    2222
    The main reason why you should never ignore warnings is because they're telling you that you did something strange, which would almost invariably be something very wrong. That would mean that what you wrote does not do what you think it does. Especially when that something wrong involves pointers, there's even a likelihood that your program will crash.

    But what's more insidious are the subtle errors that corrupts your data. If you're writing to a file, then that file could end up being corrupted. If you're really unlucky, you won't notice the problem until it's done a lot of damage.

    That is why you need to pay attention to warnings and to correct the code until you are able to compile without warnings. Only then can you say that your code compiles cleanly. Never ignore warnings!

    One problem that these implicit declarations can cause is corruption of the arguments that you pass to the function. A classic case was presented to us in my C class back in 1990. We were using Turbo C, which was still fairly new at the time. The instructor had us write a short program that would display the return value of sqrt(7), only we weren't to #include math.h -- for that matter, since it was the first or second class meeting, we didn't even know about including header files yet. The compiler implicitly declared the function and the linker was able to find it in the library files, so it generated an executable which we ran. And got an answer that was totally wrong. The compiler had implicitly declared sqrt as taking an int argument and returning an int, whereas in the header file it's declare to take and return doubles. Once we included math.h, it worked just fine.

    I've tried that experiment since then and couldn't get the same failure as we had gotten before, as if the compilers had gotten smarter about such errors. But the original 1990 experiment still shows how implicit declarations can cause subtle errors to creep in.

    Conclusion: Never rely on implicit declarations. Always declare everything explicitly.
  14. #8
  15. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    142
    Rep Power
    2
    I've tried that experiment since then and couldn't get the same failure as we had gotten before, as if the compilers had gotten smarter about such errors.
    I'm actually guilty of doing this quite a few times.
    I never gave it much thought because it gave the same result.

    but after reading your post, I see I should include the header file even if it does work, because it might return unexpected results later, for example when the program gets more complex.

    Conclusion: Never rely on implicit declarations. Always declare everything explicitly.
    thank you, I'll be sure to remember this.
  16. #9
  17. Contributing User

    Join Date
    Aug 2003
    Location
    UK
    Posts
    5,112
    Rep Power
    1803
    C does not require prototypes, but not using them means that:
    1. The compiler will not check the argument types for you
    2. It assumes the function returns an integer.

    Sometimes you get all the arguments right, and either the function does return an int an you get away with it. But it is nonetheless foolhardy. The compiler is issuing warnings asva form of static analysis of code quality. Always fix the warnings if you care about code quality. If you don't then people who do care about such things will be far less willing to assist you.

    Unlike C, C++ does require prototypes and will generate an error. You could use C++ compilation (even on your C code) as a further quality check.
  18. #10
  19. No Profile Picture
    Contributing User
    Devshed Newbie (0 - 499 posts)

    Join Date
    Jun 2013
    Posts
    142
    Rep Power
    2
    Always fix the warnings if you care about code quality. If you don't then people who do care about such things will be far less willing to assist you.
    thanks for the advice.
    since yesterday, I've learned to check the log for any errors.
    I realized I've been compiling a lot of programs ignoring the warnings.

    also I saw that in the cases when I couldn't find anything wrong with the code, but the program didn't work properly, almost always the solution was in these warnings.

    Comments on this post

    • dwise1_aol agrees : And the novice programmer was suddenly enlightened. ("The Zen of Programming")

IMN logo majestic logo threadwatch logo seochat tools logo