1753819 Members
8932 Online
108805 Solutions
New Discussion юеВ

method promotion in 'C'

 
yogiraj
Advisor

method promotion in 'C'

Hi all,
Does HP 'C' support method promotion e.g

main()
{
a( char*, int)
}

a( char *arg)
{
printf(arg);
}
What are possibilities that linker will try to promote call a(char *, int) to a(char *).

(Also how to enroll group hpux-devtools ?)
I have came accross the above behaviour, not sure if it is because I have defined() and called() method a() in two different archives and linked both in a.out (without extern'ing in the caller() arhcive)

I have attached sample program

From plain logic point of view this shouldn't have worked and this has cost me hours. As in my program I couldn't understand how call to two different methods having nothing almost nothing in common except their names go intermingled.
when a(char *, char *) should have been called, linker was calling a(char *, JNI*) and vice-versa

If its a bug and compiler & linker versions are to be held responsible, would appreciate acknowledgement that it has been fixed in latest releases.

Comp & link :
/opt/ansic/bin/cc:
LINT A.11.01.25171.GP CXREF A.11.01.25171.GP
HP92453-01 A.11.01.25171.GP HP C Compiler
$ Sep 8 2000 23:13:51 $

/usr/ccs/bin/ld:
$Revision: 92453-07 linker linker crt0.o B.11.16.01 030316 $
HP aC++ B3910B X.03.37.01 Classic Iostream Library
HP aC++ B3910B X.03.37.01 Language Support Library
ld_msgs.cat: $Revision: 1.85 $
92453-07 linker command s800.sgs ld PA64 B.11.38 REL 031217
patilyogi
6 REPLIES 6
A. Clay Stephenson
Acclaimed Contributor

Re: method promotion in 'C'

After looking through your code, you seem to be bothered by the fact that the linker linked the function that you called when you passed in only one actual parameter but was declared with two formal parameters. Note that you protoyped the function correctly so the compiler was happy. The "mistake" occurred in the linker but the linker simply uses the first matching symbol it finds; it doesn't have a clue about the parameters a function has; it simply matches the name of the object -- in this case a function.

Fundamentally (and since you mention methods) you are confusing C and C++; in C++ these two funtions would have different symbol names eventhough they both are called as times2 in the C++ code.

int times2(int a, int b)
{
return((a + b) * 2);
}

int times2(int a)
{
return(a * 2);
}

C++ does not use a different linker, so how does this work? The key to understanding this is namemangling. These two functions are given different symbol names when the object code is generated so that the linker has no problem finding one unique symbol.
Namemangling is also the reason it rarely works to mix a library created on one vendor's compiler with code generated by another vendor's compiler. There are no well-defined standards for the naming conventions.

Since you used cc to compile these source files no namemanging occurred and the linker did just what it was supposed to do. This was a case of pilot error not bad compiler/linker design.


If it ain't broke, I can fix that.
A. Clay Stephenson
Acclaimed Contributor

Re: method promotion in 'C'

I should also add that this is the reason well-disciplined programmers put their function prototypes in a common include file
rather than adding them as needed to each source files so that the compiler can detect
formal/actual parameter mismatches.
If it ain't broke, I can fix that.
yogiraj
Advisor

Re: method promotion in 'C'

Thanks and I do agree, sometimes we get carried away by C++ in midst of 'C' and that programmer should make sure that he has a method declaration in context before calling it. As you said through common header or atleast an extern in source.

But it sounds strange sometimes that it will choose the first matching symbol enountered, ignoring formal args declared and defined and will try to execute the symbol.

In the sample code
1. In caller.c func callee(char ,int ) has been called without any declaration in context.

2. Actual decl and defn in callee.c is callee(char *)

What happened to the 'int' that I passed as an actual arg ?

My prog links to Oracle and JVM helper libs both have some function names common, oracle ecpects an oracle specific structure and 2 args while JVM expects a JVM* and 5 other args.
During runtime, program trying oracle function straightway executes JVM function with oracle struct and 2 other args. Most probably assuming/assigning uncommon types args to NULL.
Opposite happens in above sample where actuals are trimmed.

Not sure if in such cases linker should raise an error atleast a warning or decide on its own to manipulate runtime args.

cheers
Yogi
patilyogi
A. Clay Stephenson
Acclaimed Contributor

Re: method promotion in 'C'

In the case where a calling function is passed an incorrect number of parameters what happens is this:

The calling function pushes whatever number of arguments on the stack. That 'whatever' is determined by the arguments supplied in the function call itself.

The called function pops off the stack whatever number of parameters that it's formal declaration indicates. In almost all C implementations, the first argument is the last to be pushed. They are then popped one at a time as needed.

In your case the 2nd (int) argument was pushed by the calling function but not popped by the called function.

Again, you seem to want the linker to do some sort of magic to fix your mistakes. The linker has to allow variable number of parameters (it really knows nothing about the parameters; that the job of the object code itself) otherwise functions with legitimate variable number of arguments (e.g. printf) would be impossible.

Interestingly, languages which do not allow variable numbers of parameters typically push their arguments from first to last -- so that the last argument is at top-of-stack but languages which allow variable numbers of paramters (like C) push last to first so that the first argument is at TOS.
If it ain't broke, I can fix that.
A. Clay Stephenson
Acclaimed Contributor

Re: method promotion in 'C'

By the way, your confusion (and this is not meant as criticism) over how parameters are passed is a good reason why I think ALL programmers should be exposed at least minimally to assembly language. It gives one a very good grounding in how function calls and returns are actually implemented. Sometimes arguments and returns use an ordered set of registers ; sometimes the stack is used; and sometimes a combination of the two is used ---- but knowing these low-level mechanisms helps to avoid confusion in the use of higher-level languages.
If it ain't broke, I can fix that.
Dennis Handly
Acclaimed Contributor

Re: method promotion in C

>Does HP 'C' support method promotion e.g

 

As Clay said, this is C and not C++ with overloading and mangling.

 

a(char*, int);    // This is a declaration not a call?
a(char *arg) {

 

This is illegal in C99 because the parms don't match the arguments.

If the first was really a call, the compiler assumes the first prototype is: int a(...)

It may give a warning about a mismatch when it sees the definition.

 

>From plain logic point of view this shouldn't have worked and this has cost me hours.

 

That's why there are C prototypes and lint.  And why C++ was invented.

 

>There are no well-defined standards for the naming conventions.

 

There is the IA64 ABI which defines mangling.

 

>What happened to the 'int' that I passed as an actual arg?

 

It is left unused in a register.

 

>Not sure if in such cases linker should raise an error

 

Unless you are Pascal or C++, the linker just matches by name.

 

>The calling function pushes whatever number of arguments on the stack. That 'whatever' is determined by the arguments supplied in the function call itself.

 

For register machines, there only is a simulated stack, no pushes nor pops.  The parms are put into registers with overflow left stored on a parm area.

 

>The called function pops off the stack whatever number of parameters that it's formal declaration indicates.

 

There is no popping.  The callee uses the registers or loads from the parm area.

For IA64, there are register frames.

 

>In almost all C implementations, the first argument is the last to be pushed.

 

For PA32 the parms are stored from high to low, the reverse of the stack direction.

For PA64, the parms are stored from low to high, the same direction as the stack.  But it has to have an AP or frame pointer.


For IA64, the stack grows from high to low and the parms are stored from low to high.

In all three cases, the parm area is of fixed size, the maximum of any call in that function.

 

>and sometimes a combination of the two is used

 

Yes, depending on how many parms (and their sizes) are passed.