?
Solved

looks like a prototype but really isn't?

Posted on 2005-04-05
28
Medium Priority
?
374 Views
Last Modified: 2010-04-15
I have a function that is prototyped in a header file:


extern long foo(long in_val);

Then, in one of my C files, it is sort of prototyped (if that's the right word)

void bar()
{
   long lng1, lng2, foo();
    ...
   lng2 = foo(lng1);
}

Am I correct in recalling that the "declaration" of foo within the function is not really
a protoype and, consequently, is OK without the argument to the function?

Thanks
Steve

0
Comment
Question by:Stephen Kairys
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 14
  • 6
  • 5
  • +2
28 Comments
 
LVL 22

Assisted Solution

by:grg99
grg99 earned 80 total points
ID: 13709314
I'd take out that "long ..., ...,  foo() declaration!    

Can't see any upside to having it.

0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13709328
but is there any harm? I think it's been there for years and there's not been a problem, at
least to my knowledge :)
Thanks
0
 
LVL 22

Expert Comment

by:grg99
ID: 13709639
Problem is, if foo()'s real prototype gets changed to return something other than a long, you're overriding it with that local definition.

Or if the real prototype gets lost, then foo() gets redeclared to take the default (int) parameters,  bad.

0
Technology Partners: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13709660
Agreed.

So, what exactly is that "extra" decl. of foo anyhow? What confuses me is that it takes
no parameters....why doesn't the compiler see that, and think this is a parameter-less
function?
thanks
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13710935
One more thing:

So, which takes precedence:
the  real prototype in my .H file,
or this pseudo-prototype (for lack of a better word) in the C file?

In other words, when the function is called, will it still recogniize the actual prototype?
Thanks

0
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 13711261

Hi Steve,

>> Am I correct in recalling that the "declaration" of foo within the function is not really a protoype and, consequently, is OK without the argument to the function?


Yes and no.  Mostly no.

foo() is already prototyped.  Within function bar(), you call foo().  Because foo() is prototyped, the call (the parameter list) must agree with the prototyped definition.

Had foo() not been prototyped, the call within bar() could be most anything that you want.  The format used here would become the "default prototype" and all subsequent calls within this source program would have to agree with the format used here.

If you prototype a function to have paramaters, you'll need to include them on the function call.


Good Luck,
Kent
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13711431
Kent,
Looks like  I did not ask my question clearly.
What I was asking was:

As you said, foo() is already prototyped (say in func.h)

extern long foo(long in_val);     (1)

Then, in one of my C files, it is sort of prototyped (if that's the right word)

void bar()                              (2)
{
   long lng1, lng2, foo();           (3)
    ...
   lng2 = foo(lng1);   <------------------  (4)
}

My question is: on the call to foo() pointed to by the arrow above, wHICH takes
precedence:  the real prototype on line (1) or the funky one  on (3)?

Thx

0
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 13711903

Depending on the level of your compiler, the call to foo() at line 3 is an error.  You're not prototyping the function, you're trying to call it as part of the stack initialization.

On older C systems, you couldn't do this:

int Func (void)
{
  int a=0;
  int b;
}

because the compiler would interpret 'a=0' as executable code.  'int b' was interpretted as a declaration out of order.

Your example does the same thing as it attempts to call foo() in the declarations.  It does not "recast" the prototype.


Kent

0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13712421
>>Your example does the same thing as it attempts to call foo() in the declarations.  It does not "recast" the prototype.

Interesting. I alwas thought that having foo() in such a context  served to
"announce" its returntype.

Anyhow, how about this case:

In my H file

extern long foo(long in_val);     (1)

In the C file, near the top of the file

Private long foo();                    (2)

Will (1) still take precedence over (2) ??
Thanks


0
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 13712806

Private is a C++ word.  :)

However, you should be able to cast it as:

static long foo();


In this case, you'll use the locally defined version instead of the library version.


Kent
0
 

Accepted Solution

by:
dtvjho earned 240 total points
ID: 13717966
stevefromc,

Your source line
    long lng1, lng2, foo();
is actually using K & R format.

In case you didn't know, K & R was the original C language from the 1970s. In K&R C, function prototypes can include a return type, but the argument list within the parentheses cannot contain data types, only argument names. The data types go on succeeding lines, as in:
    foo(a, b)
    int a;
    int b;
    {
        /* Function code */
    }

When ANSI C compilers see a function list that is empty, they turn off parameter checking for that prototype. This was intended for backward compatibility. When the compiler sees foo(), it makes no assumptions on what the args actually are. Since in your code a legit ANSI prototype with a real argument list was seen earlier, the compiler won't alter the list. This explains why the later call to foo compiles without error.

In light of the above, grg99's statement that foo "gets redeclared to take the default (int) parameters" is incorrect. There are no default parameters, as ANSI compilers will treat the empty list as an unknown.

Unlike the argument list, the return type *is* checked in both K&R and ANSI C. Since your code specifies it to be long in both the K&R and ANSI prototypes, they match, and no error is generated.

Jim Olson
0
 

Assisted Solution

by:dtvjho
dtvjho earned 240 total points
ID: 13717999
In my prior posting, I made a boo-boo:

When ANSI C compilers see a function list that is empty, they turn off parameter checking for that prototype.

The word "function" is wrong. The line should be:

When ANSI C compilers see an argument list that is empty, they turn off parameter checking for that prototype.
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13718048
Jim,

Very informative and interesting.

Now, would the same apply if intead of:
>>    long lng1, lng2, foo();
within a function body,

I had

long foo()
near the top of the C file. Will C still ignore it since
it already "saw" the real prototype??

Gee whiz...wouldn't it be nice if the compiler could
warn you about this "extra" prototype?

Thanks again.

0
 

Assisted Solution

by:dtvjho
dtvjho earned 240 total points
ID: 13718164
If the real prototype was seen first, then the K&R prototype can be in any location farther down, and type checking of the argument list will still be turned off, and the real list would remain unaltered.

Just to mention it, if the K&R prototype came first, it would define the return type with an unknown argument list. If an ANSI prototype came later, the argument list would be taken verbatim. The only chance of an error is if the ANSI prototype used a different return type.

As for issuing warnings, many compilers these days contain a command-line argument that will prevent the compilation of K&R code. You might see it described as "require prototypes" (meaning ANSI prototypes).  In the K&R days, prototypes were not of much use since only the return type was checked, so prototypes weren't ever required. This gives an edge to ANSI compilers which can require them, now that argument lists get checked.
0
 
LVL 12

Expert Comment

by:stefan73
ID: 13720079
Looks like you can combine variable and prototype declaration:

#include <stdio.h>

long a(void),b=5,c(); /* Yuck */

int main(){
    long a();
    printf("%ld %ld %ld\n",a(),b,c());
    return 0;
}

long a(void){
    return 1;
}

long c(){
    return 2;
}

...but better remove this K&R declaration. It doesn't do you any good.
0
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 13720914

Hi Jim,

I didn't even think about a K&R definition.  Good catch and a good description!


Kent
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13720969
Thanks for checking in, Kent.

Gotta love C...I'll tell you, I'm glad that I learned PASCAL
before learning "C"...at least I got to learn good
programming habits :)
0
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 13721045


>>I'm glad that I learned PASCAL before learning "C"...

I learned them in that order, too.  I can remember cursing PASCAL because its strong type casting made it tough to do some of the things that I wanted to do.

Then I learned a whole new batch of cursing terminology to go along with C's "You coded it so you must know what you're doing" mentality.  I didn't know when I was well off!

:)

0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13721085
..and actually the system that I coded stayed in Pascal until its
demise in 1999 when  everyone was converted to a system
written in C...oh, for the good old days of var, writeln
and acutally using the words "function" and "procedure" :)
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13721227
OK. Here we go.

Jim I'm giving you points (thanks to your informative
and detailed answer), split amongst your 3 comments.

Grg99, assisted points to you for your remark about
removing the "extra" prototype; however, that is not
to say that the function not be prototyped properly
elsewhere.

Thanks to all.
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13721273
..and sorry for the low number of points, I'm just
about out of points (for now) on my account.
Thanks again,
stevefromc
0
 
LVL 46

Expert Comment

by:Kent Olsen
ID: 13721310

Hey Steve,

And don't forget that PASCAL allows you to do things like:

  if (NOT true ())
  then
    false ();
  else
    maybe ();


It's just not as pretty in C.   ;)

0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13723342
Hey Jim,
I know this question is closed, but another scneario just
hit me:

what if you have a prototype:
void foo (short a);
in my H file

and then in my C file:
void foo (long a);

which takes precedence?

or even worse,

what if you have a prototype:
void foo (short a);
in my H file

and the actual function implementaion has
void foo (long a)

Thanks
stevefromc

0
 

Expert Comment

by:dtvjho
ID: 13727085
Since none of the four prototypes are in K&R format (they're all in ANSI), the compiler will catch both incidents and complain. The rule is this: the first prototype seen by the compiler normally wins. If that prototype is ANSI, it defines both return type and arg list. If that prototype is K&R, it defines only the return type (the arg list is ignored and left undefined).

The next prototype seen by the compiler will fail if anything is different. The exception is that an unknown arg list will be successfully (and quietly) redefined by an ANSI prototype.
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13728238
Jim,

Actually  (and with max warning level), my compiler did NOT complain as I would have liked.
Under both 16-bit and 32-bit the only errors I got were when mixing int_32 (which is always
4 bytes) and int (which is 4 bytes in 32-bit, 2 bytes in 16-bit).

#include <stdio.h>

typedef unsigned short      uint_16;
typedef signed short      int_16;
typedef unsigned long      uint_32;
typedef signed long      int_32;



// The compiler should object under 32-bit since int is 4 bytes and int_16 is 2 bytes but it does not
void test_proto(int a);

void test_proto(int_16 a)
{
      
}

// The compiler should object under 32-bit since int_16 is 2 bytes and int is 4 bytes but it does not
void test_proto2(int_16 b);

void test_proto2(int b)
{
      
}

// Here, the compiler objects, "Type of parameter 1 does not agree with definition"
// in both 16 and 32 bit.  Surprising for 32-bit since int and int_32 are same size.
void test_proto3(int a);

void test_proto3(int_32 a)
{
      
}

void test_proto4(int_32 b);

// Here, the compiler objects, "Type of parameter 1 does not agree with definition"
// in both 16 and 32 bit.  Surprising for 32-bit since int and int_32 are same size.
void test_proto4(int b)
{
      
}




int main()
{
       return 0;
}


Also, speaking of ANSI  PROTO, I found this in our code (in a C file)

int add_trans ANSI_PROTO((TRANSACTION *, int));
-is the "ANSI_PROTO" really necessary?

Thanks
0
 

Expert Comment

by:dtvjho
ID: 13728578
Your interpretations are correct. The first two test prototypes are revealing compiler bugs.

The 3rd and 4th prototypes should not have complained since the data types are of the same size. My guess is that the compiler writer thought that defining a prototype using a variant of long is not a match for a variant of int, i.e. int != long by definition. My answer is that C provides for automatic conversion of compatible data types, but this may only apply to executable code and not something compile-time such as prototypes.

As for ANSI_PROTO(), this looks like a macro. You should be able to remove it, but first find the definition to make sure it is nothing more than a wrapper.
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13728673
Thanks. again Jim.

Oh for the days of...

function convert(var base : integer) : integer  

:)

amazed I remember this syntax, it's been 5 years :)
0
 
LVL 4

Author Comment

by:Stephen Kairys
ID: 13728682

>>function convert(var base : integer) : integer  

>>amazed I remember this syntax, it's been 5 years :)


...so he says. Of course I need a semicolon after the function header....
0

Featured Post

Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

An Outlet in Cocoa is a persistent reference to a GUI control; it connects a property (a variable) to a control.  For example, it is common to create an Outlet for the text field GUI control and change the text that appears in this field via that Ou…
Summary: This tutorial covers some basics of pointer, pointer arithmetic and function pointer. What is a pointer: A pointer is a variable which holds an address. This address might be address of another variable/address of devices/address of fu…
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.
The goal of this video is to provide viewers with basic examples to understand and use conditional statements in the C programming language.
Suggested Courses
Course of the Month9 days, 1 hour left to enroll

764 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question