Link to home
Start Free TrialLog in
Avatar of Stephen Kairys
Stephen KairysFlag for United States of America

asked on

looks like a prototype but really isn't?

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

SOLUTION
Avatar of grg99
grg99

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Stephen Kairys

ASKER

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
Avatar of grg99
grg99

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.

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
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

Avatar of Kent Olsen

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
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


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

>>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



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
ASKER CERTIFIED SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.

SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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.

Hi Jim,

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


Kent
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 :)


>>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!

:)

..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" :)
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.
..and sorry for the low number of points, I'm just
about out of points (for now) on my account.
Thanks again,
stevefromc

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.   ;)

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

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.
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
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.
Thanks. again Jim.

Oh for the days of...

function convert(var base : integer) : integer  

:)

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

>>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....