gnu@hoptoad.uucp (John Gilmore) (05/29/87)
I think I've found a problem with the C standard. (greek chorus: It says that functions with variable numbers of "so what else arguments cannot be called unless a function is new?") prototype is in scope. The standard Unix open() call can take either two or three parameters, but you are not required to #include any header files to use it. Now, if you are using the third operand, you will be including <sys/file.h> to get O_CREAT, but if not, it seems to be perfectly acceptable to use a small integer constant as the second operand. It seems that if a compiler really believed the restriction in the draft standard, it would not be able to correctly compile many Unix programs which haven't heard of three operand open() or <sys/file.h>. -- Copyright 1987 John Gilmore; you may redistribute only if your recipients may. (This is an effort to bend Stargate to work with Usenet, not against it.) {sun,ptsfa,lll-crg,ihnp4,ucbvax}!hoptoad!gnu gnu@ingres.berkeley.edu
jss@hector.UUCP (05/29/87)
In article <2210@hoptoad.uucp> gnu@hoptoad.uucp (John Gilmore) writes: >I think I've found a problem with the C standard. (greek chorus: >It says that functions with variable numbers of "so what else >arguments cannot be called unless a function is new?") >prototype is in scope. > >It seems that if a compiler really believed the restriction in the >draft standard, it would not be able to correctly compile many Unix >programs which haven't heard of three operand open() or <sys/file.h>. It is not a restriction on the compiler (or compiler writer), it is a requirement on the (application) programmer. The intention, as I read it, is to allow a C compilation system to use a different calling sequence for functions with known numbers of arguments and those (like printf) with variable numbers of arguments. Whether this is desirable will depend on pragmatic considerations, such as the overheads associated with permitting variable numbers of arguments. I doubt that any UNIX compiler will be written that varies its calling sequences in this way, but I could be wrong. At least the ANSI standard requires compilation systems to have some way to deal with functions that are called with varying numbers of arguments. This was not required by K&R. (Although a C compilation system that didn't support "printf" would probably not have many users.) Jerry Schwarz
brett@wjvax.UUCP (Brett Galloway) (05/31/87)
In article <2619@ulysses.homer.nj.att.com> jss@hector (Jerry Schwarz) writes: >In article <2210@hoptoad.uucp> gnu@hoptoad.uucp (John Gilmore) writes: >>I think I've found a problem with the C standard. (greek chorus: >>It says that functions with variable numbers of "so what else >>arguments cannot be called unless a function is new?") >>prototype is in scope. >It is not a restriction on the compiler (or compiler writer), it is a >requirement on the (application) programmer. The intention, as I >read it, is to allow a C compilation system to use a different >calling sequence for functions with known numbers of arguments and >those (like printf) with variable numbers of arguments. How about functions called with function pointers? I am not that familiar with the details of function prototyping in the standard, but will it be possible to invoke functions with variable arguments with function pointers? If not, that will be quite annoying (and will break an application that I have written (under UNIX C). How about functions called with function pointers? It seems to me that the only way separate calling sequences for non-variable argument and variable argument functions could work would be to disallow function pointers to the latter type. In that case, this seems a serious deficiency of the requirement. At minimum, it breaks an application that I have written under UNIX C (bsd), which otherwise adheres to the varargs(3) specifications. -- ------------- Brett Galloway {pesnta,twg,ios,qubix,turtlevax,tymix,vecpyr,certes,isi}!wjvax!brett
guy%gorodish@Sun.COM (Guy Harris) (06/01/87)
> How about functions called with function pointers? I am not that familiar > with the details of function prototyping in the standard, but will it be > possible to invoke functions with variable arguments with function pointers? From the October 1, 1986 draft: 3.5.3.3 Function declarators (including prototypes) ... Here are two more intricate examples: int (*apfi[3])(int *x, int *y); declares an array "apfi" of three pointers to functions returning "int". Each of these functions has two parameters that are pointers to "int".... which implies that the type of a function pointer, just like the type of a function, includes the types of its arguments as well as the type of its result. As such, you can declare int (*pintvarargs)(int i, ...); which is a pointer to a function whose first argument is an "int" and which may have 0 or more optional arguments after that. A function pointed to by "pintvarargs" can be called with a variable-length list of arguments, as long as that list has at least one argument and the first argument is of a type that can be coerced to "int". The declaration int (*pintarg)(int i); declares a pointer to a function whose *only* argument is an "int". A function pointed to by "pintarg" may only be called with one argument, which must be of a type that can be coerced to "int". The deprecated old-style declaration int (*pwhoknows)(); is, I infer, equivalent to int (*pwhoknows)(...); which declares a pointer to a function which may have 0 or more optional arguments. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
gwyn@brl-smoke.ARPA (Doug Gwyn ) (06/02/87)
In article <2210@hoptoad.uucp> gnu@hoptoad.uucp (John Gilmore) writes: >The standard Unix open() call can take either two or three parameters, >but you are not required to #include any header files to use it. Now, >if you are using the third operand, you will be including <sys/file.h> >to get O_CREAT, but if not, it seems to be perfectly acceptable to use >a small integer constant as the second operand. I don't understand the point you're trying to make. open() is not an ANSI C function at all. POSIX requires that you #include three headers (which does seem like two too many; <stat.h> should not be required) for portable invocation of open(). (<sys/file.h> is NOT one of these.) Non-POSIX UNIX-like systems are free to do whatever they please. The only way for an application programmer to correctly, portably code his own IMPLEMENTATION of open() in ANSI C would be to use the <stdarg.h> mechanism; however, implementors of ANSI C can implement it any way they choose -- for most existing systems the implementation would be unchanged. In particular, for most existing systems, code that invokes open() without including <fcntl.h> would continue to work, but portability cannot be assured (which is simply a fact of life).
bright@dataio.UUCP (06/02/87)
In article <931@wjvax.wjvax.UUCP> brett@wjvax.UUCP (Brett Galloway) writes:
-How about functions called with function pointers? I am not that familiar
-with the details of function prototyping in the standard, but will it be
-possible to invoke functions with variable arguments with function pointers?
-If not, that will be quite annoying (and will break an application that I
-have written (under UNIX C).
The secret is in the declaration:
int (*fp1)(int); /* pointer to function with fixed # of arguments */
int (*fp1)(char *,...); /* pointer to function with variable arguments that
returns an int */
int (*fp)(); /* obsolete */
gnu@hoptoad.UUCP (06/04/87)
Several people didn't understand what I was saying, so let me try again. This is strictly an ANSI C issue; there is no interaction with POSIX. Let's suppose that someone writes a compiler such that if a function is not declared with (...) then it cannot be called with a variable number of arguments. In other words, if the function is not declared at all, it can't take a varying number of arguments. If the function is declared the old way, e.g. "int open();" it also will not work. You have to declare it as e.g. "int open(...);" for this compiler to pass the arguments properly. This is a valid way to write a compiler, according to ANSI C. This might occur in a machine with overlapping register windows, such as a Pyramid or various RISC machines. Typically, arguments would be passed in registers, but for calls to vararg functions, they would get pushed on a stack, or an argument count passed in secretly, or some such. If such a compiler was ever used to compile a Unix program, trouble would arise. Unix programs traditionally don't #include anything when they are going to use the open() call, so there is no include file that could declare "int open(...);" for them. If the user calls open() with two arguments, without having declared the "open" function in any way, the compiler must assume that it is a two-argument function, since all variable-argument functions MUST be declared with "...". Sez so right in the standard. Remember, the compiler has to know which kind of function it is -- fixed-args or variable-args, since it implements parameter passing differently for the two kinds. When it passes these two arguments to the open() library routine, the arguments will be in the wrong place, because the open() library routine will have to be written to assume variable arguments, since indeed open() can be called with a variable number of arguments. In fact, another module of the same source program could call open() with three arguments. This means that such a compiler could not be compatibly used on a Unix system, even though it meets all the requirements of the ANSI C standard, and indeed BECAUSE it ENFORCES some of the requirements of the ANSI C standard. I can see a few possible ways around this but they all involve making the varargs interface pass arguments compatibly with the non-varargs interface, or massive kludgery (recognize the string "open"; bring in different libraries at link time; append the argument count to the names of fixed-arg functions; and similar rot). If implementations are going to be forced to pass arguments compatibly, the standard might as well not restrict users to declaring all their varargs functions, and should not encourage implementors to require it. How do the Pyramid and MIPS compilers handle open() calls now? -- Copyright 1987 John Gilmore; you may redistribute only if your recipients may. (This is an effort to bend Stargate to work with Usenet, not against it.) {sun,ptsfa,lll-crg,ihnp4,ucbvax}!hoptoad!gnu gnu@ingres.berkeley.edu
gwyn@brl-smoke.UUCP (06/04/87)
In article <2242@hoptoad.uucp> gnu@hoptoad.uucp (John Gilmore) writes: >This means that such a compiler could not be compatibly used on a Unix >system, even though it meets all the requirements of the ANSI C standard, I think a more precise statement would be: Much existing code from UNIX systems would have to be changed (at least to the extent of #including a header that declares the open() function properly) in order to successfully work under a C implementation that (for perhaps good and sufficient reason) uses a different function linkage for a fixed versus a variable number of arguments. It is important to note that MOST UNIX C implementations will not have this problem. This is just a fact of life for some machine architectures. It may also be worth noting that much UNIX software is atrociously written and wouldn't port well without considerable effort anyway. Several people have been working on improving this situation; they ought to insert #include <fcntl.h> as required while they're at it.
michael@stb.UUCP (06/05/87)
In article <20119@sun.uucp> guy%gorodish@Sun.COM (Guy Harris) writes: >> How about functions called with function pointers? I am not that familiar >> with the details of function prototyping in the standard, but will it be >> possible to invoke functions with variable arguments with function pointers? > >From the October 1, 1986 draft: > > 3.5.3.3 Function declarators (including prototypes) > > ... > > Here are two more intricate examples: > > int (*apfi[3])(int *x, int *y); > > declares an array "apfi" of three pointers to functions returning > "int". Each of these functions has two parameters that are > pointers to "int".... > >which implies that the type of a function pointer, just like the type >of a function, includes the types of its arguments as well as the >type of its result. As such, you can declare > > int (*pintvarargs)(int i, ...); > >which is a pointer to a function whose first argument is an "int" and >which may have 0 or more optional arguments after that. A function >pointed to by "pintvarargs" can be called with a variable-length list >of arguments, as long as that list has at least one argument and the >first argument is of a type that can be coerced to "int". The >declaration > > int (*pintarg)(int i); > >declares a pointer to a function whose *only* argument is an "int". >A function pointed to by "pintarg" may only be called with one >argument, which must be of a type that can be coerced to "int". > >The deprecated old-style declaration > > int (*pwhoknows)(); > >is, I infer, equivalent to > > int (*pwhoknows)(...); > >which declares a pointer to a function which may have 0 or more >optional arguments. > Guy Harris > {ihnp4, decvax, seismo, decwrl, ...}!sun!guy > guy@sun.com Wait a sec. Would you please explain how the following can be done: I have a dispatcher routine, that takes a pointer to a function, some args, does some munching on the args, and calls the pointed to routine with 3, 4, or 5 args. Each routine called is expecting a known, fixed # of args, yet the pointer used is with variable args. So, according to the above, I have to declare the function pointer as variable args, which activates one calling convention, yet the routines are fixed args, and expecting another calling convention. -- : Michael Gersten seismo!scgvaxd!stb!michael : The above is the result of being educated at a school that discriminates : against roosters.
karl@haddock.UUCP (Karl Heuer) (06/06/87)
In article <2242@hoptoad.uucp> gnu@hoptoad.uucp (John Gilmore) writes: >Let's suppose that someone writes a compiler such that [varargs functions >must be declared with ellipses]. If such a compiler was ever used to compile >a Unix program, [with no #include and with open() not explicitly declared,] >trouble would arise. Well, an ANSI compiler is not even obliged to provide an open() function, so there's no problem. :-) Instead of answering your question, I'd just like to mention that I think the addition of a third argument to open() was a really dumb move by AT&T. This causes open() to be weakly variadic without need, and creates nonportable code since neither BSD nor Research UNIX has implemented this, to the best of my knowledge. Now, I'll grant that it's useful to have some of the features of creat() and open() available in one system call. I only disagree with the implementation. I would've made a new system call, cropen(path, mode|flags); powerful enough to supersede both creat() and open() (which could then be moved into section 3 and/or marked as deprecated). Other systems could have a SysV emulation library that defines cropen(3) in terms of open(2) and creat(2), where possible. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint (Note "mode|flags" implies the Read/Write/RdWr option would be higher bits. Alternately, they could be separate arguments.)
mash@mips.UUCP (06/06/87)
In article <2242@hoptoad.uucp> gnu@hoptoad.uucp (John Gilmore) writes: ..... >This might occur in a machine with overlapping register windows, such >as a Pyramid or various RISC machines. Typically, arguments would be >passed in registers, but for calls to vararg functions, they would get >pushed on a stack, or an argument count passed in secretly, or some >such... >I can see a few possible ways around this but they all involve making >the varargs interface pass arguments compatibly with the non-varargs.... >How do the Pyramid and MIPS compilers handle open() calls now? MIPS does the following: callee: the code is the same, regardless of whether the callee is vararg'd or not: 0-4 arguments are placed in registers args 5-? are placed onto the stack [not pushed, the stack doesn't move until the actual function call, if at all] space is left in the stack for args 1-4. (non-long args complexify all this, but that's the idea) caller: usually gets the args from the registers, or the stack, as needed saves any of args 1-4 into space reserved on the stack, if compiler "suspects" & operator being applied to the arguments, even indirectly, as in x = &arg2; z = *--x; varargs declaration makes sure that compiler suspects the right things! Thus, normal access to the variables is thru the registers, and the first 4 args are only saved into memory if they need to be, or if the compiler has reason to suspect they need to be. Statistically, the arguments almost NEVER get saved unless they really need to. -- -john mashey DISCLAIMER: <generic disclaimer, I speak for me only, etc> UUCP: {decvax,ucbvax,ihnp4}!decwrl!mips!mash, DDD: 408-720-1700, x253 USPS: MIPS Computer Systems, 930 E. Arques, Sunnyvale, CA 94086
guy@gorodish.UUCP (06/06/87)
> Wait a sec. Would you please explain how the following can be done: > > I have a dispatcher routine, that takes a pointer to a function, some args, > does some munching on the args, and calls the pointed to routine with 3, > 4, or 5 args. Each routine called is expecting a known, fixed # of args, > yet the pointer used is with variable args. So, according to the above, > I have to declare the function pointer as variable args, which activates > one calling convention, yet the routines are fixed args, and expecting > another calling convention. Trivial. Have the argument to the dispatcher, instead of being a pointer to a function with a variable number of arguments, be a union of a pointer to a function with three arguments, a pointer to a function with four arguments, and a pointer to a function with five arguments. Since you have three separate calls, use the three different members of the union in the three calls. End of problem. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
guy@gorodish.UUCP (06/06/87)
> Instead of answering your question, I'd just like to mention that I think the > addition of a third argument to open() was a really dumb move by AT&T. This > causes open() to be weakly variadic without need, and creates nonportable > code since neither BSD nor Research UNIX has implemented this, to the best > of my knowledge. Nope. 4.2BSD implemented the three-argument "open". Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
karl@haddock.UUCP (06/09/87)
In article <20539@sun.uucp> guy%gorodish@Sun.COM (Guy Harris) writes: >>... neither BSD Research has implemented this, to the best of my knowledge. >Nope. 4.2BSD implemented the three-argument "open". Damn. They didn't have enough bad ideas of their own, they had to copy AT&T's? :-) (Sorry about the misinformation; I should have RTFM.) Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
dhesi@bsu-cs.UUCP (06/10/87)
Re: Much discussion about how open() can break C code on an ANSI- compliant system if a function prototype is omitted. The original discussion arose because somebody said that AT&T's open() system call could take either 2 or 3 arguments, causing possible problems on systems that implemented function calls with a known argument count differently from function calls with a variable argument count. Somebody suggested that 4.2BSD code would break too. It should be noted that the 4.2BSD manual page for open(2), dated 2 July 1983, and the 4.3BSD manual page for open(2), dated May 14 1986, both clearly show that open() has three, and exactly three, parameters. The value of the third parameter is simply ignored in most cases, which is quite different from saying that the presence of the parameter is optional. AT&T's manual page for open(2), as supplied with Microport System V/AT, does show the third argument as being optional. -- Rahul Dhesi UUCP: {ihnp4,seismo}!{iuvax,pur-ee}!bsu-cs!dhesi
guy@gorodish.UUCP (06/10/87)
> It should be noted that the 4.2BSD manual page for open(2), dated 2 > July 1983, and the 4.3BSD manual page for open(2), dated May 14 1986, > both clearly show that open() has three, and exactly three, > parameters. The value of the third parameter is simply ignored in most > cases, which is quite different from saying that the presence of the > parameter is optional. It should also be noted that plenty of 4.[23]BSD code uses "open" as if the third argument were options, so the fact that the manual does not explicitly indicate the third parameter as optional probably does not mean that one is obliged to provide it. Plenty of 4.[23]BSD code will break on systems that don't support "open" with the third argument optional. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
stevesu@copper.UUCP (06/14/87)
In article <514@haddock.UUCP>, karl@haddock.UUCP (Karl Heuer) writes: > I think the addition of a third argument to open() was a really dumb > move by AT&T. This causes open() to be weakly variadic without need, > and creates nonportable code since neither BSD nor Research UNIX has > implemented this, to the best of my knowledge. I really like the new, optional third argument to open(). It is one of the few cases I know of in the Unix world in which a truly new feature was added to an existing call in a backwards-compatible way. I first came across it in 4.xBSD (which does have it, by the way) and was astonished that Berkeley had done something that clever, since backwards-incompatibility is usually their battle cry. (I now know that it was implemented first at AT&T, and emulated in BSD.) Of course, code using it is less portable, but then so is code using any new feature. I only use a three-argument open when I need its extra semantics, otherwise I use old-fashioned creat() and/or two-argument open(). I will grant that functions with variable numbers of arguments are a problem. However, backwards incompatibility is a bigger problem. I insist that extensions be made in a backwards compatible way, to avoid breaking existing code. If a case can be made for adding functionality to an existing call (rather than adding a new call) and if the new functionality requires new arguments, then varargs is the only way to go. The optional third argument to open is specified correctly, in that its presence is signaled by a previous argument (the O_CREAT bit in the second argument). There is no need for the callee to discover the number of arguments in the stack frame, which can be done reliably on the VAX but on few other architectures. Implementors of architectures with register or other non-stack argument passing mechanisms will simply have to solve the varargs problem (as long as the language provides sufficient information, as a function prototype does.) You need varargs for printf(), which I think everybody agrees is an appropriate and useful application of varargs, so why not use it for open() as well, even if the case for the optional argument is a little less strong? Steve Summit stevesu@copper.tek.com
mouse@mcgill-vision.UUCP (der Mouse) (06/23/87)
In article <20538@sun.uucp>, guy%gorodish@Sun.COM (Guy Harris) writes: >> Wait a sec. Would you please explain how the following can be done: >> [dispatcher which calls a fxn passed by a pointer as an argument, >> with 3, 4, or 5 args. Each fxn expects known arg pattern.] > Trivial. Have the argument to the dispatcher, instead of being a > pointer to a function with a variable number of arguments, be a union > of a pointer to a function with three arguments, a pointer to a > function with four arguments, and a pointer to a function with five > arguments. Except that this makes it effectively impossible to use the dispatcher. Consider the call to the dispatcher that would have been written (under the old K&R paradigm) as int fxn(); ... dispatcher(....,fxn); How does on write the corresponding thing? (Please forgive any syntax errors, I don't have a copy of the draft - and won't until I can get one machine-readable!) int fxn(int x; int y; double z); ... dispatcher(....,fxn); Oops. The argument to the dispatcher is not of type int (*)(int,int,double) but of type union{int(*)(int,int,double);int(*)(int,int,double,double);} instead. Ugly. der Mouse (mouse@mcgill-vision.uucp)
mouse@mcgill-vision.UUCP (der Mouse) (06/23/87)
In article <1125@copper.TEK.COM>, stevesu@copper.TEK.COM (Steve Summit) writes: > In article <514@haddock.UUCP>, karl@haddock.UUCP (Karl Heuer) writes: >> I think the addition of a third argument to open() was a really dumb >> move by AT&T. [...] since neither BSD nor Research UNIX has >> implemented this, to the best of my knowledge. As both stevesu and someone else (Chris Torek I think?) point out, BSD 4.2 and 4.3 both have three-argument open(). > I really like the new, optional third argument to open(). It is one > of the few cases I know of in the Unix world in which a truly new > feature was added to an existing call in a backwards-compatible way. > I first came across it in 4.xBSD (which does have it, by the way) and > was astonished that Berkeley had done something that clever, since > backwards-incompatibility is usually their battle cry. (I now know > that it was implemented first at AT&T, and emulated in BSD.) Well, I don't know about the AT&T implementation, but the BSD open() most emphatically does not have an optional third argument! It has three, exactly three, arguments. It just happens that on most BSD machines, you can get away with passing fewer arguments that the routine wants provided it ignores the extra ones. This means that you can get away with pretending it's optional, but that doesn't make it optional at all. Wait for the day you have to port to a machine whose compiler treats optional arguments differently - it'll be the day this burns you. der Mouse (mouse@mcgill-vision.uucp)
guy%gorodish@Sun.COM (Guy Harris) (06/26/87)
> Well, I don't know about the AT&T implementation, but the BSD open() > most emphatically does not have an optional third argument! It has > three, exactly three, arguments. It just happens that on most BSD > machines, you can get away with passing fewer arguments that the > routine wants provided it ignores the extra ones. The BSD implementation very closely resembles the System III/System V implementation, so the argument is as optional in one as it is in the other. > This means that you can get away with pretending it's optional, but that > doesn't make it optional at all. Wait for the day you have to port to a > machine whose compiler treats optional arguments differently - it'll be > the day this burns you. Actually, it'll be the day it burns the person who ports UNIX to that machine; "open()" used to take two arguments, and there are plenty of programs left around that weren't changed when "open" was changed. This is, I presume, why Karl Heuer complained about the 3-argument "open"; introducing it technically rendered *all* programs that used a two-argument "open" invalid! Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
guy%gorodish@Sun.COM (Guy Harris) (06/26/87)
> Except that this makes it effectively impossible to use the dispatcher. > Consider the call to the dispatcher that would have been written (under > the old K&R paradigm) as > > int fxn(); > ... > dispatcher(....,fxn); > > How does on write the corresponding thing? /* * This would presumably appear in an #include file. */ typedef union { int (*three_argument)(int, int, double); int (*four_argument)(int, int, double, double); int (*five_argument)(int, int, double, double, double); } function_pointer_passed_to_dispatcher; int fxn(int x; int y; double z); extern return_type_of_dispatcher dispatcher(various_argument_types, function_pointer_passed_to_dispatcher funcp); function_pointer_passed_to_dispatcher temporary; temporary.three_argument = fxn; dispatcher(..., temporary); Yes, this may be ugly, but it's type-correct, and may even be necessary in some implementations. Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com
pdg@ihdev.ATT.COM (Joe Isuzu) (06/29/87)
In article <821@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes: >Well, I don't know about the AT&T implementation, but the BSD open() >most emphatically does not have an optional third argument! It has >three, exactly three, arguments. I'll just add this for completeness. According to SVID, the open call is: int open(path,oflag,mode) Three arguments, none optional. Now everybody go back and change all of the code you have ever written. :-} -- Paul Guthrie "Another day, another Jaguar" ihnp4!ihdev!pdg -- Pat Sajak
stuart@bms-at.UUCP (Stuart D. Gathman) (06/30/87)
In article <817@mcgill-vision.UUCP>, mouse@mcgill-vision.UUCP (der Mouse) writes: > In article <20538@sun.uucp>, guy%gorodish@Sun.COM (Guy Harris) writes: > > Trivial. Have the argument to the dispatcher, instead of being a > > pointer to a function with a variable number of arguments, be a union . . . > Consider the call to the dispatcher that would have been written (under > the old K&R paradigm) as > int fxn(); > ... > dispatcher(....,fxn); > How does on write the corresponding thing? (Please forgive any syntax > int fxn(int x; int y; double z); > ... > dispatcher(....,fxn); *** Solution A typedef union { int (*type3)(int,int,double); int (*type4)(int,int,double,double); } disp_fxn; ... dispatcher(....,(disp_fxn)fxn); I know, this is not allowed, but I wish it was! Perhaps it should be: dispatcher(....,((disp_fxn)fxn).type3); or dispatcher(....,(disp_fxn.type3)fxn); Would this be portable? Uglier, but I know it would work is: *** Solution B { disp_fxn temp; dispatcher(....,temp.type3=fxn); } We use indirect functions all over the place. We not been using function prototypes since some of the compilers we support don't have them. As a result, there are many bugs resulting from the wrong parm type being passed to a function called through a table. It would be nice to have a way to lint indirect function calls without the mess of 'B'. Worse yet, are dynamic indirect function calls. This is where the function pointers are themselves stored in a table! This is impossible to lint, since lint cannot guarrantee what kind of pointer will actually reside in a function pointer variable at run time. At this point, I start leaning towards O-O! -- Stuart D. Gathman <stuart@bms-at.uucp> <..!seismo!dgis!bms-at!stuart>
karl@haddock.UUCP (Karl Heuer) (06/30/87)
In article <22196@sun.uucp> guy%gorodish@Sun.COM (Guy Harris) writes: ["temporary" is a union of different flavors of functions] >temporary.three_argument = fxn; >dispatcher(..., temporary); This makes a good case for the cast-into-union feature on my wishlist. >Yes, this may be ugly, but it's type-correct, and may even be necessary >in some implementations. Yeah. Of course people won't use it if they "know" it's overkill on their vax. :-( Fortunately, the situation in question doesn't come up very often. Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint
shopiro@alice.UUCP (07/01/87)
I'd just like to mention that in C++, the prototype for open() would be int open(const char* path, int flags, int mode=0); This declares a function with three arguments, that can optionally be called with only two arguments. In that case, the compiler adds the third argument using the default value given in the declaration. Thus old code coexists with new, and type checking is not defeated. -- Jonathan Shopiro AT&T Bell Laboratories, Murray Hill, NJ 07974 research!shopiro (201) 582-4179
mikes@apple.UUCP (Mike Shannon) (07/03/87)
In article <7046@alice.UUCP> shopiro@alice.UUCP writes: >I'd just like to mention that in C++, the prototype for open() would be > > int open(const char* path, int flags, int mode=0); ^ | The above "const" brings up an interesting question: if I do: { char *pathname = "some.file"; int i; i = open(pathname, O_RDONLY) ..... } is the above declaration really OK? since the first param isn't CONST? -- Michael Shannon {apple!mikes}
am@cl.cam.ac.uk (Alan Mycroft) (07/03/87)
In article <817@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes: (Discussion re despatcher and use of unions of function types.) >Except that this makes it effectively impossible to use the dispatcher. extern dispatcher(...., union funtypes fnarg); >int fxn(int x; int y; double z); >... >dispatcher(....,fxn); > >Oops. The argument to the dispatcher is not of type >int (*)(int,int,double) >but of type >union{int(*)(int,int,double);int(*)(int,int,double,double);} >instead. Ugly. Ugly indeed. The problem is that C does not include all the operations one would expect on union types. If you ask (say) a category theorist (and can understand the answer) he will mutter about co-products and say something more precise than: if A and B are types(objects) then so is (sometimes) union(A,B). This comes along with some functions (partial or sometimes undefined in the case of the out functions). in1: A -> union(A,B) in2: B -> union(A,B) out1: union(A,B) -> A out2: union(A,B) -> B. Now we see the problem: C in its hackerish wisdom only provides the 'out' functions via the (e).member construct. The other functions one has to hack using temporaries (see below). Now one should sympathise with those who wish casts of objects into a union type containing that object -- they only want a very natural concept. In C we could say union intorptr { int a; char *b;}; extern f(union intorptr); g() { f((union intorptr)3);} NOT IN ANSI. However, this omission leads to the following as the 'best' allowed form for g: g() { union intorptr temp; temp.a = 3; f(temp); } I fail to see that this is more readable (note we have forged an 'in' function using an 'out' function and assignment). Lest I get flamed, I will not point out the even nastier version using casts between differing pointers which does not work for functions due to the ANSI code/data pointer disinction. Motto: once in a while listen to these crazy pure mathematicians - they can't spent all day contemplating their navels and fail to notice anything significant. While we're on about this, similar reasoning may be used to contemplate why C makes it so hard to extract more than 1 result from a struct-returning function like 'ldiv'.
bts@sas.UUCP (Brian T. Schellenberger) (07/05/87)
In article <817@mcgill-vision.UUCP>, mouse@mcgill-vision.UUCP (der Mouse) writes: > In article <20538@sun.uucp>, guy%gorodish@Sun.COM (Guy Harris) writes: > >> Wait a sec. Would you please explain how the following can be done: > >> [dispatcher which calls a fxn passed by a pointer as an argument, > >> with 3, 4, or 5 args. Each fxn expects known arg pattern.] > > <then he suggests that the following problem occurs: > > int fxn(int x; int y; double z); > ... > dispatcher(....,fxn); > > Oops. The argument to the dispatcher is not of type > int (*)(int,int,double) > but of type > union{int(*)(int,int,double);int(*)(int,int,double,double);} > instead. Ugly. Why not just use typedefs and casts to good effect; eg, typedef union{ int (*)(int,int,double); int (*)(int,int,double,double) } dispatch_fptr; dispatcher( ...., (dispatch_fptr)fxn ); A thousand forgivenesses if I am mistaken and ANSI in fact prohibits the obvious (I should wait 'til Monday to post this, so I can check my copy of the standard to be sure, but . . .). A cast seems the obvious solution. I *would* suggest that if ANSI disallows this, it should be fixed. --Brian. ...!rti!mcnc!sas!bts