0

I'm new to programming and I read before defining a function we need to define it's prototype.And if we don't want our function to accept any value then we write void as parameter. So just to check it I wrote this small program where while defining function prototype I wrote it's parameter as void and while writing it's definition wrote int a as it's parameter (hoping that I will get an error, but I never got one).Then I compiled and ran the program it gave me this output

This program prints the square of all the numbers starting from 1 to 3

the square of 1 is 1 :

the square of 2 is 4 :

the square of 3 is 9 :

After this I changed the parameter in definition to float a (just to check if program will still work) and this time i got a different output as shown below

This program prints the square of all the numbers starting from 1 to 3

the square of 1 is 0 :

the square of 2 is 0 :

the square of 3 is 0 :

.

Can any one please explain what's happening here ? why my compiler is not throwing an error and why I'm getting two completely different output for int and float ? I'm using visual studio professional 2013 with update 4 !

//program to calulate square using functions 

#include <stdio.h>
#pragma warning (disable:4996)

int square(void);

int main()
{

    int i;

    printf("This program prints the square of all the numbers starting from 1 to 3");

    for (i = 1; i <= 3; i++)  
            printf("\n\nthe square of %d is %d : \t",i,square(i));

    getch();
    return 0;
}


square(a)
{

    a = a*a;
    return a;

}

1.program screenshot with int as parameter definition

Rishi Shukla
  • 306
  • 1
  • 3
  • 13
  • On one hand I want to answer undefined behavior, on the other I want to answer backwards compatibility with older standards (or even pre-standard). – Some programmer dude Jul 19 '15 at 17:59
  • @JoachimPileborg sir feel free to answer both of them ! :) – Rishi Shukla Jul 19 '15 at 18:00
  • Also, what is the warning you disable? You should not disable warnings as they are often signs of you doing something you're not supposed to, and which might lead to undefined behavior. – Some programmer dude Jul 19 '15 at 18:01
  • "void as parameter" means that there is no argument. – BLUEPIXY Jul 19 '15 at 18:01
  • You may want to heed the problems [shown here](http://ideone.com/3MvqQf). I dunno what version of MS compiler you're using, but perhaps try something from this decade? – WhozCraig Jul 19 '15 at 18:03
  • Compile with C99 or C11 compiler and watch the warnings. – too honest for this site Jul 19 '15 at 18:04
  • 1
    @JoachimPileborg i disabled the warnings where visual studio always wanted me to use scanf_s instead of scanf ! – Rishi Shukla Jul 19 '15 at 18:04
  • 2
    "i disabled the warnings ...". I would take that already as reason for close vote (cannot be reproduced). You disable warnings and wonder why your compiler does not complain? – too honest for this site Jul 19 '15 at 18:05
  • @Olaf That may answer why i'm not getting warnings (well it should have given me an error instead ). but does that answer for two different answer for float and int ? – Rishi Shukla Jul 19 '15 at 18:09
  • I have the [answer](http://port70.net/~nsz/c/c11/n1570.html) to all your questions. (As the question is known, the answer is not `42`). – too honest for this site Jul 19 '15 at 18:11
  • This will explain what disable statement does in my program http://stackoverflow.com/questions/16883037/remove-secure-warnings-crt-secure-no-warnings-from-projects-by-default-in-vis – Rishi Shukla Jul 19 '15 at 18:14
  • @Olaf sir the thing which is bothering me is why defined function is accepting values as argument when it's parameter is defined as void ? I have disabled the warnings not the errors (and here I should have got an error ) as function prototype defines what parameters/arguments my function is going to take ! – Rishi Shukla Jul 19 '15 at 18:29
  • The image is difficult to read because it's scaled down, but if you open it in a new tab (right-click, then "Open Image in New Tab", or your browser's equivalent) it's much easier to read. – Keith Thompson Jul 20 '15 at 17:47

2 Answers2

2

Old C standard allows declaring functions without parameters, and then parameters are assumed to be of type int. Everything works ok as long as everything matches, but funny things may happen if things don't match.

It all comes down to calling convention. The calling code puts parameters somewhere (stack and registers usually), and then the function takes them from somewhere, and if this "somewhere" is same, and the data types match, everything works. And when they don't match, you get undefined behaviour.

So the int version works because everything matches. Compiler warns you that it can't know if your code will actually work (or give an actual error with later C standard versions, and in C++), but this is just warning, meaning it is up to you to make sure it's ok (which you really don't want to do, it's compilers job, so enable warnings and fix them!).

The float version you mention is then undefined behaviour. Anything the computer is capable of doing can happen (including breaking into your bank account and emptying it next time you use Internet banking, this is basically how a lot of malware actually infects a computer, exploiting programming errors). But here you probably get zero, because floating point parameters and return values are passed in FPU registers, which the function does not change, and the return value happens to be zero because of that.

hyde
  • 60,639
  • 21
  • 115
  • 176
0

A conforming C compiler must issue at least one diagnostic for the program in your question.

Your square function is declared as:

int square(void);

which says it takes no arguments and returns an int result. You then call it as:

square(i)

which passes one argument. This is a constraint violation, which means that a compiler must issue a diagnostic (which may be either a warning or a fatal error).

You then define it as:

square(a) { /* ... */ }

which is an old-style definition. It says that square takes an int argument and returns an int result (under the obsolete "implicit int" rule). But that definition is not visible at the point of the call, so the compiler will process the call using only the declaration.

According to Microsoft's documentation, this:

#pragma warning (disable:4996)

disables warnings for "deprecated" functions. It shouldn't apply to anything in your program, so you should still get a warning or fatal error on the incorrect call square(i).

Either your compiler is buggy or, more likely, either the code in your question or your description of the compiler's behavior is incorrect.

Please copy-and-paste the exact code from your question and try compiling it. If it really does compile without warnings or errors, you have a serious problem with your compiler or with the way you're using it.

(Of course the declaration, definition, and call to square should all be consistent, but your question is about why the compiler doesn't diagnose the error, not about how to fix it in your source code.)

As for why you get different output with int vs. float, if the declaration and definition of a function are inconsistent, any call results in undefined behavior. When you change the definition to use float, the generated code is probably passing an int value that the function incorrectly interprets as a float value. The result is meaningless.

UPDATE: Now that I've seen your screenshot, it looks like your compiler is doing something I didn't expect. It warns that the declaration int square(void) has a void parameter list. By itself, that declaration is perfectly valid; it's only a problem because the following definition defines square with an int argument. It must have decided to warn about the declaration after it saw the incompatible definition.

The thing that really surprises me is that it doesn't warn about the call square(i). That call is consistent with the definition (which follows it), but inconsistent with the declaration (which precedes it).

C is designed to be processed in one pass. The legality of a construct depends on the code that precedes it, not on what follows it.

But the only requirement imposed by the C standard is that the compiler must issue at least one diagnostic. It says nothing about the wording of that diagnostic, nor does it require it to be a fatal error. In this case, the code violates a constraint (because the declaration and definition of square are incompatible), and in my opinion it should reject the program -- but a warning satisfies the standard's requirements.

Regardless of the decisions made by the authors of the compiler, it did produce several warning messages, and you should not ignore them. It's (perhaps indirectly) pointing out problems with your code, and you should fix those problems. The fact that the compiler warned about your code is sometimes more informative than the actual content of the warnings.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
  • Sir I'm also adding the screenshot of my program and the warnings i got at the time of compilation along with the output i got ! if in case the screenshot is not visible here is the link for the image https://onedrive.live.com/redir?resid=B9B6BE8E45151B68!26664&authkey=!AHSQBZtjT2UBZG8&v=3&ithint=photo%2cjpg – Rishi Shukla Jul 20 '15 at 06:14
  • It actually warns about the call and not the declaration. See the line no. or use the [online Visual C++ compiler](http://webcompiler.cloudapp.net/) with `/TC` to compile as C. – cremno Jul 21 '15 at 03:32