home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!snorkelwacker.mit.edu!thunder.mcrcim.mcgill.edu!sobeco!philmtl!vedge!hendrik
- From: hendrik@vedge.UUCP (Hendrik Boom)
- Newsgroups: comp.std.c
- Subject: Re: mixing prototyping and non-prototyping
- Message-ID: <28616@vedge.UUCP>
- Date: 19 Aug 92 15:55:06 GMT
- References: <spuler.713749345@coral.cs.jcu.edu.au>
- Organization: Visual Edge Software, St. Laurent, Quebec
- Lines: 189
-
- spuler@coral.cs.jcu.edu.au (David Spuler) writes:
- :
- : What are the rules regarding mixing old-style and new-style functions in C
- : programs? Specifically, what mixtures must a compiler support,and which can
- : be legally allowed to bomb?
-
- Here's my standard handout on this subject:
-
- More light and heat on prototypes
-
- A close reading of the ANSI C standard reveals the following
- convoluted relationships between prototypes, old and new style
- function definitions, and function calls. Please comment,
- especially if you detect errors in my interpretation.
-
- First, some terminology.
-
- A function definition is the thing that contains
- the executable code for the function. A function declaration
- only announces that a particular name is to be used
- as a name for the function, and does not contain the
- executable code for the function. Any and all of a function
- definition, declaration, and call may contain information
- about the argument types, with varying significane.
-
- We call them parameters in a declaration or definition,
- and arguments in a call.
-
-
-
- Case: No prototypes at all.
- ---------------------------
-
- This is how old-stype K&R C worked.
-
- The interpretation by a compiler of parameters in a function
- definition and its interpretation of arguments in a call
- were independent. To lesen the pain somewhat, conversion rules
- were defined that made things slightly more likely to match up.
-
- ANSI defines the old-stype functions to worl as follows.
-
- The old-style rules apply whenever a function has neither
- been declared with prototype syntax
- nor been defined with new-style syntax.
-
- The function call applies a set of
- standard conversions, and the function definition expects
- the standard conversions to have been applied.
-
- The standard conversions at the point of call are defined
- independent of the actual parameter types expected by the
- function definition.
-
- To make this work at least some of the time,
- a function defined using old-style syntax,
- will expect its parameters to have been converted
- using the standard argument promotion rules.
-
- A function with a single real argument, such as
- f(r)real r;{ }
- will in fact expect a double.
- If you pass a double to it, the double gets passed as is.
- If you pass a real to it, the real will be converted to
- double at the point of call, and the double will be
- passed instead.
- If you pass an int, no conversion takes place. This will
- probably not work.
- If you pass a char, it will actually pass an int,
- which will probably not work.
-
- Note: machines exist where the int representation is a
- subset of the real representation. However, even on these
- machines, a double is likely to be bigger than a real
- or an int.
-
-
- Case: protoype at definition and call. (New-style rules)
- --------------------------------------------------------
-
- If you have a function declared with a prototype,
- such as
- int f(real);
- this indicates how the compiler is to call the function,
- and indicates that the parameter is to be passed by whatever
- conventions the compiler uses to pass real parameters.
- If the argument in a call is, for example, an integer,
- and the protoype indicates it should be a real,
- it will be converted to real, and passed using the parameter
- conventions for real. These might well differ from those for
- passing a double.
-
- Case: prototype at use but not at definition.
- ---------------------------------------------
-
- This can be expected to happen during transition from
- old-style to new.
-
- If the call to function f occurs in a place where a prototype
- has been declared for f, but the function definition
- (probably in a separate compilation unit) uses old-style
- parameter syntax, trouble is likely to arise.
- The caller will perform a set of conversions based on the
- prototype, and the function will expect the arguments
- to have been converted without reference to a prototype.
- If these conventions differ, the arguments get trashed
- across the interface. Ansi permits the old-new clash
- provided that the prototype define the arguments to
- have the types that they would have after conversion
- according to the non-prototype parameter conversion rules.
- This in general may differ from the types mantioned
- in the function definition.
-
- In the case of our function with the single real argument,
- f(r)real r;{ }
- the protoype must read
- f(double);
- because f will expect any real argument to have been
- converted to double before it is passed.
-
- Prototype at definition but not at use.
- ---------------------------------------
-
- This is likely to occur during transition from old to new styles
- if the function is called from a separate compilation unit,
- or if the call occurs before the prototype or definition in
- the same compilation unit.
-
- Again, this will work if the prototype declared the types
- that will result from the standard argument promotions.
- If the function is defined using new-stype syntax, the
- types of the parameters must be the same as the types in the
- prototype declaration.
-
- If a function with a single real argument is defined using
- new-style syntax:
- g(real x){ }
- then a call like g(r) will not work if the prototype for g is not
- at the point of call. Even if the argument r is in fact a real,
- and g expects a real, absence of a protoype at the point of call
- will force the real to be promoted to double and passed as a double!
-
-
- The moral
- ---------
-
- How do we use _NO_PROTO?
-
- To make code work with and without prototypes, but to take advantage
- of them when they are available, use the following conventions.
-
- (a) Include parameters in function declarations
- conditional on the absence of _NO_PROTO.
- This will provide extra checking and argument conversions
- and may detect a lot of silly errors.
-
- (b) Either
- - (b1) provide two versions of the parameter part of
- a function definition, a new-style version
- if _NO_PROTO is absent and K&R style if it is
- present,
- or
- - (b2) use only the old K&R style, but accept restrictions
- on the parameter types that occur in any prototypes.
- The parameters in the prototypes must be the ones that
- remain after the standard argument promotions,
- because a K&R function will expect these instead
- of the types actually mentioned in its code.
- Thus if the function expects a char, the prototype
- must lie and say int or unsigned int (depending on the
- platform). It the function expects a real, the
- prototype must say double.
-
- Note: For compatiblility with TAGS, the initial open
- curly brace of the function body must be at the left margin
- with the parameterds inside the #ifdef _NOPROTO . Otherwise
- TAGS will fail to notice that a function was defined at all.
-
- Note: For non-Visual-Edge readers on the net:
- _NO_PROTO is a preprocessor symbol extensively used by
- many software producers to govern the
- presence or absence of prototypes in header files.
- Its use is not dictated or mentioned by the ANSI standard.
-
- --
- -------------------------------------------------------
- Try one or more of the following addresses to reply.
- at work: hendrik@vedge.com, iros1!vedge!hendrik
- at home: uunet!altitude!ozrout!topoi!hendrik
-