[comp.lang.c] cdecl and pascal keywords

jdb@reef.cis.ufl.edu (Brian K. W. Hook) (12/27/90)

I know that C and Pascal pass parameters differently and clean up the calling
stack differently, but I was wondering whether there is a NOTICEABLE difference
in speed and size of program that uses PASCAL declarations for fixed argument
functios and the cdecl declaration for variable...e.g.

void pascal foobar ( void );

void pascal foobar ( void )
{
...
}

VERSUS:

void cdecl foobar ( void );

void cdecl foobar ( void )
{
....
}

Assume that parameters can be passed, also, just a fixed amount....I know
main() has to be declared as cdecl, but otherwise, is it possible for me
to change all of my other functions to pascal declarations without any
side effects?

And will I actually gain anything?  I know a lot fo Windows prototypes are
prototype with the PASCAL keyword.

Brian

kvitekp@jvd.msk.su (Pete Kvitek) (12/27/90)

In article <26075@uflorida.cis.ufl.EDU> jdb@reef.cis.ufl.edu (Brian K. W. Hook) writes:
>I know that C and Pascal pass parameters differently and clean up the calling
>stack differently, but I was wondering whether there is a NOTICEABLE difference
>in speed and size of program that uses PASCAL declarations for fixed argument
>functios and the cdecl declaration for variable...e.g.
>
  [ stuff deleted ]
>
>Assume that parameters can be passed, also, just a fixed amount....I know
>main() has to be declared as cdecl, but otherwise, is it possible for me
>to change all of my other functions to pascal declarations without any
>side effects?
>
>And will I actually gain anything?  I know a lot fo Windows prototypes are
>prototype with the PASCAL keyword.
>
>Brian

  The order in which parameters are pushed on the stack
  does not seem to make any speed or size difference.
  However, if procedure uses C calling conventions, then
  calling procedure is responsible for cleaning up stack
  after _every_ call, thus consuming some extra memory in
  code segment. Pascal procedure cleans up stack _before_
  returning to the caller.

  This probably explains why Windows designers choose
  pascal calling conventions since Windows code usually
  contains huge amount of references to the Windows
  libraries.

  Another reason to use pascal calling convections is to
  conserve stack space with heavily nested procedures
  (for example recourcive ones).

  > Pete
-- 
--
Pete I. Kvitek <kvitekp@jvd.msk.su>                   | Phone: (095) 328-1327
Speaking from but not for JV Dialogue, Moscow, USSR   | Fax:   (095) 329-4711

risto@tuura.UUCP (Risto Lankinen) (12/28/90)

kvitekp@jvd.msk.su (Pete Kvitek) writes:

>  Another reason to use pascal calling convections is to
>  conserve stack space with heavily nested procedures
>  (for example recourcive ones).

Hi!

This is a false assumption, at least in case of Microsoft C (using _cdecl
versus _pascal).  In either way, the stack contains the arguments of the
(possibly recursively) called function, the backed-up local frame pointer
and the return address.  There's no penalty in stack usage for using the
_cdecl even in recursive functions.

The size difference is, indeed, significant in programs using a lot of
function calls:  Using _pascal, each function *code* carries an overhead
of 1 byte (by RET nn instead of plain RET), while with _cdecl each *call*
to a function spends 3 extra bytes (by an inserted ADD SP,nnnn) for stack
clean-up.

The _cdecl is good for functions, which have variable number of arguments.
I have also seen it claimed faster than _pascal, although with i286 I dare
to doubt the significance of the difference.  Because with _cdecl the next
instruction is 'guaranteed' to be 3 bytes long (and spend a few additional
cycles for pre-fetch), while with _pascal there is a good chance the next
instruction is smaller than that (say, PUSH AX = 1 byte within nested calls,
for example).

By the way, an 'extremely optimizing' compiler could fight back a bit with
_cdecl, by leaving the stack arguments intact between calls, should there be
a (rare) piece of code, where exactly (or almost exactly) the same arguments
are used in subsequent calls, and the arguments were declared as const.

Terveisin: Risto Lankinen
-- 
Risto Lankinen / product specialist ***************************************
Nokia Data Systems, Technology Dept *  2                              2   *
THIS SPACE INTENTIONALLY LEFT BLANK * 2 -1 is PRIME!  Now working on 2 +1 *
replies: risto@yj.data.nokia.fi     ***************************************

wollman@emily.uvm.edu (Garrett Wollman) (01/02/91)

We are getting *very* far afield from the subject of C... :-(

That said, I should point out to the previous posters, that there is
*no* reason why the arguments have to be popped off the stack
immediately after every function call.  In fact, by default, gcc -O
waits to pop until there is a branch or unbranch in control-flow (or,
at any rate, that what I *think* it's doing) before popping.  You have
to specifically request -fno-defer-pop for it to stop doing this.

Of course, you can also do without a frame pointer if it strikes your
fancy--just don't try to debug!

Unfortunately, as all PC programmers know, Microsoft is (and always
has been) considerably behind the times when it comes to optimization.
I'm thinking of trying to compile the mutated, 16-bit, 8086-supporting
version of GCC so that I can get decent optimization on PC programs.
I'm also thinking of scrapping PC programming altogether, at least so
long as I have access to a Real Computer :-)

-GAWollman

Garrett A. Wollman - wollman@emily.uvm.edu

Disclaimer:  I'm not even sure this represents *my* opinion, never
mind UVM's, EMBA's, EMBA-CF's, or indeed anyone else's.

torvalds@cs.Helsinki.FI (Linus Torvalds) (01/02/91)

In article <898@tuura.UUCP> risto@tuura.UUCP (Risto Lankinen) writes:
[lots of interesting stuff deleted ...]
>By the way, an 'extremely optimizing' compiler could fight back a bit with
>_cdecl, by leaving the stack arguments intact between calls, should there be
>a (rare) piece of code, where exactly (or almost exactly) the same arguments
>are used in subsequent calls, and the arguments were declared as const.

In fact the compiler needn't be THAT optimizing to use the _cdecl to
speed up programs - it can defer stack cleanup until really necessary.
Thus instead of cleaning up the stack after EVERY call, it can call a
few functions and clean up the stack for ALL calls with one instruction
(ADD #n,A7 on mc68k etc.) This, I believe is done (optionally) by gcc.
Of course the compiler must be pretty certain that the stack doesn't get
TOO big, but it isn't (shouldn't) be that difficult to check for. IE:

	....
	pea addr		# argument on stack, then 
	bsr _func1		# call _func1

	move.l #0,-(a7)		# don't clean up, just put new arg
	bsr _func2		# on top of stack and call _func2

	addq.l #8,a7		# now clean up both call arguments
	...

Obviously, the speedup isn't dramatic, just my $ 0.02

>
>Terveisin: Risto Lankinen
>-- 
>Risto Lankinen / product specialist ***************************************
>Nokia Data Systems, Technology Dept *  2                              2   *
>THIS SPACE INTENTIONALLY LEFT BLANK * 2 -1 is PRIME!  Now working on 2 +1 *
>replies: risto@yj.data.nokia.fi     ***************************************

	Linus Torvalds		torvalds@cs.helsinki.fi

dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) (01/04/91)

In <26075@uflorida.cis.ufl.EDU> jdb@reef.cis.ufl.edu (Brian K. W. Hook) writes:

>...but I was wondering whether there is a NOTICEABLE difference
>in speed and size of program that uses PASCAL declarations...

This belongs in comp.lang.pascal, does it not?

Seriously, please don't assume that comp.lang.c readers will be able to
answer questions about nonstandard extensions of the C programming
language.  The "pascal" keyword is used by MS-DOS-specific compilers,
and a better place to ask the question will be one of the MS-DOS
newsgroups.

However...

The effect of using the "pascal" keyword is to tell the compiler that
it need not assume that traditional C style function calls, with a
posibly variable number of parameters, will be used.  The compiler can
thus generate code that allows the called function to pop the stack
before it returns, rather than inserting stack-popping code after each
call to each function.  Difference in speed:  probably not noticeable.
Difference in code size: a few bytes (let's say about 2 bytes) saved
each time any function is called.  If a function is called 10 times,
that means 20 bytes saved by making that function a "pascal" function.

In theory, there is no need for a "pascal" keyword if you're using ANSI
C, since the compiler knows whether or not a prototype is in scope, and
can generate efficient or inefficient code accordingly.  In practice,
it seems (unverified suspicion) that most MS-DOS compilers don't take
advantage of the presence of ANSI C prototypes for such optimization
but do take advantage of the "pascal" keyword.  This could be because
of the fear that the user might link the object code resulting from his
C source with an assembly language program, or out of the knowledge
that most MS-DOS users don't use "lint" and can therefore not check
function calls for consistency across files.
--
History never         |   Rahul Dhesi <dhesi%cirrusl@oliveb.ATC.olivetti.com>
becomes obsolete.     |   UUCP:  oliveb!cirrusl!dhesi

karl@ima.isc.com (Karl Heuer) (01/05/91)

In article <2847@cirrusl.UUCP> dhesi%cirrusl@oliveb.ATC.olivetti.com (Rahul Dhesi) writes:
>In theory, there is no need for a "pascal" keyword if you're using ANSI C...

Unless the compiler is going to do cross-file analysis (e.g. with a fixup at
link time), it would have to assume that all non-variadic functions are
pascal-like.  (It's irrelevant whether or not a prototype is in scope, since
	int main(void) { return f(1); }
and
	extern int f(int);
	int main(void) { return f(1); }
are equivalent programs, irregardful of whether f() is defined with or without
a prototype in its own source file.)

But if the compiler treats non-variadic functions and variadic functions
differently, it would break the common (but non-ANSI) usage
	/* no <stdio.h>! */
	int main() { printf("hello, world\n"); return 0; }
because it doesn't know that printf() is variadic.

Conclusion: an implementation must do one of the following:

[0] Be prepared to distinguish variadic from non-variadic functions at link
time.

[1] Treat all functions as caller-pop (unless otherwise indicated by a
nonstandard keyword like "__pascal").

[2] Treat all non-variadic functions as callee-pop, and break old programs
such as the above.  (A warning "no prototype for printf()" helps here.)

[3] Recognize "printf" and friends as reserved words even when <stdio.h> is
missing.

Karl W. Z. Heuer (karl@ima.isc.com or uunet!ima!karl), The Walking Lint

jdb@reef.cis.ufl.edu (Brian K. W. Hook) (01/05/91)

> "CDECL and PASCAL keywords...shouldn't this be in comp.lang.pascal?"

*ahem*  Granted, I am new to the net, but I was not sure whether to post a
question RE:CDECL and PASCAL to comp.lang.c or comp.os.msdos.programmer...
The keywords CDECL and PASCAL are part of DOS compiler C language extensions,
and thus I posted here.  I have assumed that comp.lang.c is, in fact, for
all flavors of C, and that comp.std.c is for standard C (ANSI or K&R?).

For those that answered, thank you for your assistance.  As an aside, maybe
there should be:

comp.lang.c.msdos
comp.lang.c.ansi
comp.lang.c.kr
comp.lang.c.sun

etc...posting on comp.os.msdos.programmer invariably gets me few answers
since many are posters familiar with pascal or asm...and I need help with
C....

Brian

jbr0@cbnews.att.com (joseph.a.brownlee) (01/07/91)

In article <2847@cirrusl.UUCP>, dhesi%cirrusl@oliveb.ATC.olivetti.com
(Rahul Dhesi) writes:
> Seriously, please don't assume that comp.lang.c readers will be able to
> answer questions about nonstandard extensions of the C programming
> language.  The "pascal" keyword is used by MS-DOS-specific compilers,
> and a better place to ask the question will be one of the MS-DOS
> newsgroups.

Well, it is also commonly used on the Macintosh, where the ROM software is
all written assuming PASCAL calling conventions.  The keyword "pascal" is
generally used in one of two ways:

    .	to prototype a ROM (or other library) routine.

    .	to force one of your own functions to use PASCAL conventions.  This
	is necessary, for example,  when a ROM routine expects a procedure
	pointer and you pass a pointer to your own routine written in C.

-- 
   -      _   Joe Brownlee, Analysts International Corp. @ AT&T Network Systems
  /_\  @ / `  471 E Broad St, Suite 1610, Columbus, Ohio 43215   (614) 860-7461
 /   \ | \_,  E-mail: jbr@cblph.att.com     Who pays attention to what _I_ say?
 "Scotty, we need warp drive in 3 minutes or we're all dead!" --- James T. Kirk