g-rh@cca.CCA.COM (Richard Harter) (06/13/87)
Here is one that has me puzzled. We have a C program which
runs on a large variety of UNIX boxes (system V and bsd), VMS, and PRIMOS.
One of the files has code that looks like this:
extern int (*command_table[])();
.....
command_processor() {
....
int (*command)();
....
command = command_table[n];
....
(*command)(args);
....
}
The declaration for command_table declares it as an array of
pointers to functions returning int. (Confirmed by cdecl) The declar-
ation for command declares it as a pointer to a function returning int.
We pick off the appropriate command and execute it. Now, on a wide
variety of UNIX systems the line "(*command)(args);" may be written
as "(command)(args)". We have observed:
(a) On most UNIX machines (VAX BSD and Sun in particular) either
form is acceptable and will compile and execute correctly. Moreover
lint will accept either form without complaint. (VMS C also takes
either form without complaint or error.)
(b) One vendor's compiler (I won't name it because I don't have the
log sheets at hand) gives a compilation warning for (*command)().
(This is a UNIX box.)
(c) The PRIMOS C compiler rejects (command)(args) and insists
upon (*command)(args)
First Question: Is the above code correct and legal C, or are we
overlooking something subtle?
Second Question: Why do both alternatives pass lint and execute
correctly on most machines?
Third Question: Are we correct in assuming that the compiler for
vendor X is broken?
Fourth Question: We are strongly committed to portable code and would
like the code to be the same, in so far as possible, to be the same for
all operating systems that we deal with. we have good reasons for using
a jump table. What is the best way to code this with full portability?
--
Richard Harter, SMDS Inc. [Disclaimers not permitted by company policy.]
stevesu@copper.UUCP (06/14/87)
In article <16673@cca.CCA.COM>, g-rh@cca.CCA.COM (Richard Harter) writes: > ...on a wide variety of UNIX systems the line "(*command)(args);" > may be written as "(command)(args)". We have observed: > > (a) On most UNIX machines (VAX BSD and Sun in particular) either > form is acceptable and will compile and execute correctly. > > (b) One vendor's compiler gives a compilation warning for (*command)(). > > (c) The PRIMOS C compiler rejects (command)(args) and insists > upon (*command)(args) I believe that the compiler mentioned on observation (b) is incorrect. This may be a perpetuation of the (possibly misguided) trend of issuing warnings for &array. I have always thought about it this way: if "command" is a pointer to a function, then I have to slap a "*" in front of it before I have a real function that I can stick an argument list on and call. Many compilers seem to make the "*" optional, reasoning that the only possible use for a function pointer, especially in a function call context, is to indirect on it and call it. I wish they wouldn't, since this only leads to confusion and misunderstanding, as you've discovered. (Throwing well-defined rules out the window and applying weird heuristics in an attempt to do what the programmer meant and not what he said violates what I feel to be one of the fundamental tenets of the Unix philosophy. One of the reasons that programming on VMS is such a screaming nightmare is that there are very few hard-and-fast rules you can apply in attempting to predict the system's behavior, since so many undocumented special cases have been inserted so as to "do the right thing.") So, to answer your question, (*command)(args) is correct and should be maximally (but, sadly, not universally) portable. Steve Summit stevesu@copper.tek.com
guy@sun.UUCP (06/15/87)
> > (b) One vendor's compiler gives a compilation warning for (*command)(). > > > > (c) The PRIMOS C compiler rejects (command)(args) and insists > > upon (*command)(args) > > I believe that the compiler mentioned on observation (b) is > incorrect. The compiler mentioned on observation (b) is incorrect. According to K&R: 7.1 Primary expressions ... A function call is a primary expression followed by parentheses containing a possibly empty, comma-separated list of expressions which constitute the actual arguments to the function. The primary expression must be of type "function returning..." ... And, if "command" is of type "pointer to function returning...", "*command" is clearly of type "function returning. ANSI C is a bit different: 3.3.2.2 Function calls Constraints The expression that denotes the function called shall have type ``pointer to function''. Since an expression of type "function" gets converted to an expression of type "pointer to function" that points to that function, in most cases - see 3.3.0.1 Lvalues and function designators ... A "function designator" is an expression that has function type. If a function designator appears in a context where such an operand is not permitted, it is converted to a pointer as described in \(sc 3.2.2.1. The result is not a function designator and 3.2.2.1 Arrays, functions, and pointers ... Except when used as an operand where a function designator is permitted, an identifier declared as ``function returning "type"'' is converted to an expression that has type ``pointer to function returning "type".'' - either (*command)(args) or command(args) is permitted by ANSI C. So it seems that K&R permits (b) but not (c), while ANSI C permits both of them. I'm not sure I like this either, but that's life. > This may be a perpetuation of the (possibly > misguided) trend of issuing warnings for &array. Actually, ANSI C changes the *meaning* of "&array", so that it is an expression of type "pointer to array" rather than an expression of type "pointer to what the array is made out of". As such, this trend will come to an end once the ANSI C standard leaves draft status. (Fortunately, this is one of the easiest pieces of ANSI C to implement in PCC - all you have to do is delete some code, namely the code in "mip/cgram.y" that tests whether the "&" operator is being applied to something of type "array" or "function", issues a warning, and eliminates the "&" operator. It's always nice to improve something without having to add code....) -- Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com (or guy@sun.arpa)
chris@mimsy.UUCP (06/15/87)
In article <16673@cca.CCA.COM>, g-rh@cca.CCA.COM (Richard Harter) writes: >int (*command)(); >.... >(*command)(args); vs >"(command)(args)" >One vendor's compiler ... gives a compilation warning for (*command)(). >... The PRIMOS C compiler rejects (command)(args) and insists >upon (*command)(args). The PRIMOS C compiler is within its rights; K&R have said to use the first form. The dpANS recommends the second form. When the draft standard is adopted, and assuming that its recommendation still stands, the PRIMOS compiler will have to be changed. The compiler that gives a warning for (*command)(args) is making useless noise. Incidentally, PCC accepts all sorts of strange things: x() { int (*f)(), g(); f = g; (*f)(1); f(1); (***f)(1); g(1); (*g)(1); (**g)(1); } If you look at it properly, this is not so strange after all: Values of type `function' are changed to values of type `pointer to function' in most contexts. Why not change them thus even in function call contexts, and then allow pointer-to-function '(' argument-list ')' ';' and accept either form? -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7690) Domain: chris@mimsy.umd.edu Path: seismo!mimsy!chris
levy@ttrdc.UUCP (06/15/87)
In article <16673@cca.CCA.COM>, g-rh@cca.CCA.COM (Richard Harter) writes: < extern int (*command_table[])(); < ..... < command_processor() { < .... < int (*command)(); < .... < command = command_table[n]; < .... < (*command)(args); < .... < } < < One vendor's compiler (I won't name it because I don't have the < log sheets at hand) gives a compilation warning for (*command)(). < (This is a UNIX box.) I'm curious what the warning is. Could the compiler be griping because you do nothing with the return value from (*command)(args) ? (Lint should complain about this too.) -- |------------dan levy------------| Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa, | an engihacker @ | vax135}!ttrdc!ttrda!levy | at&t data systems division | Disclaimer: try datclaimer. |--------skokie, illinois--------|
g-rh@cca.CCA.COM (Richard Harter) (06/16/87)
In article <1763@ttrdc.UUCP> levy@ttrdc.UUCP (Daniel R. Levy) writes: >< .... >< (*command)(args); >< .... >< One vendor's compiler (I won't name it because I don't have the >< log sheets at hand) gives a compilation warning for (*command)(). >< (This is a UNIX box.) > As I recall, the warning was to the effect that the * was not needed. As to lint. I trimmed the code -- the actual statement was of the for 'value = (*command)(args))'. However lint should not complain and does not if a function is explicitly or implicitly declared int and you are consistent either in using or not using the return value. The cast to void kludge postdates lint by a fair margin. I won't say that there are no version extant of lint that will complain about consistently ignoring an int return, but I have run on a fair number of machines, and I haven't seen it. We don't use void casts or enums as a matter of policy. We aren't interested in using pretty little frills that may or may not be universally available. Nor are we interested in challenging people's compilers and discovering the obscure ways they are broken. Our coding precepts are very simple -- if there is any prospect that it might not work on any of the machines that we support, don't use it. Special cases and non-portability code are too expensive to bother with. -- Richard Harter, SMDS Inc. [Disclaimers not permitted by company policy.]
daveb@geac.UUCP (Dave Brown) (06/16/87)
In article <7048@mimsy.UUCP> chris@mimsy.UUCP (Chris Torek) writes: >If you look at it properly, this is not so strange after all: >Values of type `function' are changed to values of type `pointer >to function' in most contexts. Why not change them thus even in >function call contexts, and then allow > pointer-to-function '(' argument-list ')' ';' >and accept either form? Probably for the same reason that caused so much discussion over automatic changing of array-name to pointer-to-array -vs- taking the address of an array-name: the more the compiler does for you, the more it has to guarantee that what it did will never cause future problems. Friendlyness -> Complexity -> Defaults -> PL/1 My solution? Promote all the niceties to a language called c+, c+-, c[1] or whatever and remove some of the warts on regular c. Then call *that* language c--. --dave (then *REAL PROGRAMMERS* would use c-- instead of fortran) brown
jfh@killer.UUCP (John Haugh) (06/19/87)
In article <16769@cca.CCA.COM>, g-rh@cca.CCA.COM (Richard Harter) writes: > In article <1763@ttrdc.UUCP> levy@ttrdc.UUCP (Daniel R. Levy) writes: > >< .... > >< (*command)(args); > >< .... > > As I recall, the warning was to the effect that the * was not > needed. As to lint. I trimmed the code -- the actual statement was > of the for 'value = (*command)(args))'... Sorry if this has been said this week, I said it a few weeks back. Function declarations are wierd in C. The only language that seems to get pointers reasonably normal (or non-wierd) is BLISS. But then I hate all of those silly little dots. [ This is just inews fodder ] Heres the short form on function declarations. Write Dennis if you want more, or better still go buy the book. int func(); /* function returning integer */ int *func(); /* function returning pointer to integer */ int (*func)(); /* pointer to function returning integer */ int *(*func)(); /* pointer to function returning * to int */ How do you use these guys to get an integer after you call them? i = func (); /* returns integer, use that */ i = *(func ()); /* returns pointer, dereference it */ i = (func) (); /* use pointer, take return value */ i = *((func) ()); /* use pointer, dereference return value */ There it is in a nutshell, you really don't need the * unless the function is declared int (**func)();, then you have pointer to pointer to a function returning an integer. > Richard Harter, SMDS Inc. [Disclaimers not permitted by company policy.] - John. Disclaimer: No disclaimer. Whatcha gonna do, sue me?
john@riddle.UUCP (Jonathan Leffler) (06/22/87)
>In article <16673@cca.CCA.COM>, g-rh@cca.CCA.COM (Richard Harter) writes: >> ...on a wide variety of UNIX systems the line "(*command)(args);" >> may be written as "(command)(args)". For what it is worth, on the ICL Perq, the syntax command(args) was interpreted as (*command)(args) which makes some sort of sense (all function names can be thought of as pointers to functions). We only learnt that this was unusual when we ported to other compilers (lots of 'em), and they only accepted (*f)(). ------ My views are mine. Jonathan Leffler
peter@sugar.UUCP (Peter DaSilva) (06/26/87)
> There it is in a nutshell, you really don't need the * unless the function > is declared int (**func)();, then you have pointer to pointer to a function > returning an integer. According to K and R (1) You do need the *, and (2) (func)() should be identical to func(). I'm not sure I approve of compilers taking it upon themselves to turn func() into (*func)() without telling me, and I certainly won't assume that it will work in any compiler I might come across. The meaning of pointers to functions should be well defined. Lately the meanings of all sorts of things has become problematical. While I'm here, let me bitch about structure passing. I really don't think there's any reason for passing anything larger than a double on the stack. If you want to have a routine to copy it into local storage, you can always allocate another copy on the stack in the routine and memcpy() it. It won't be significantly slower. On the other hand I've been bitten more than once by leaving out an ampersand and having 10,000 bytes pushed on an 8,000 byte stack. UNIX => C but C !=> UNIX.
francus@cheshire.columbia.edu (Yoseff Francus) (06/30/87)
In article <225@sugar.UUCP> peter@sugar.UUCP (Peter DaSilva) writes: >> There it is in a nutshell, you really don't need the * unless the function >> is declared int (**func)();, then you have pointer to pointer to a function >> returning an integer. > >According to K and R (1) You do need the *, and (2) (func)() should be >identical to func(). I'm not sure I approve of compilers taking it upon >themselves to turn func() into (*func)() without telling me, and I certainly >won't assume that it will work in any compiler I might come across. The >meaning of pointers to functions should be well defined. Lately the meanings >of all sorts of things has become problematical. > >While I'm here, let me bitch about structure passing. I really don't think >there's any reason for passing anything larger than a double on the stack. >If you want to have a routine to copy it into local storage, you can always >allocate another copy on the stack in the routine and memcpy() it. It won't >be significantly slower. On the other hand I've been bitten more than once >by leaving out an ampersand and having 10,000 bytes pushed on an 8,000 byte >stack. UNIX => C but C !=> UNIX. True ususally you want to pass the address of a strucuture. But what if you change the values of the structure in the function, and DON'T want to know about the changes after returning from the function???? Yoseff ****************************************************************** yf In Xanadu did Kubla Khan a stately pleasure dome decree But only if the NFL to a franchise would agree. ARPA: francus@cs.columbia.edu UUCP: seismo!columbia!francus
mlinar@poisson.usc.edu (Mitch Mlinar) (06/30/87)
In article <4761@columbia.UUCP> francus@cheshire.columbia.edu.UUCP (Yoseff Francus) writes: >In article <225@sugar.UUCP> peter@sugar.UUCP (Peter DaSilva) writes: >>> There it is in a nutshell, you really don't need the * unless the function >>> is declared int (**func)();, then you have pointer to pointer to a function >>> returning an integer. >> > >True ususally you want to pass the address of a strucuture. But what if >you change the values of the structure in the function, and DON'T want >to know about the changes after returning from the function???? > >Yoseff > Maybe I am not too familiar with the BIG frame architectures, but I am somewhat familiar with items of the Sun/uVaxII genre on down. The issue actually boils down to efficiency of structures and the simple fact is: Operations on static variables are ALWAYS faster than operations on auto variables. Now, this could just be a weakness in the uP instruction set or in the C compilers themselves, but I have yet to see the reverse. If you insist upon doing big structs as "auto" (stack) variables, then there is probably not much difference in speed - both passing a structure on the stack and copying to a local "auto" are slow. However, using stack operations on these machines is MUCH slower than passing a pointer and copying to a local static area. Secondly, MANY C compilers still do not support pushing anything other than simple arguments on the stack. Pushing whole structures is NOT portable in my book. As it turns out, almost ALL efficient C compilers handle static memory allocation much better than stack, too. So, you are not saving any REAL memory, although swap decreases. (Use of static is REQUIRED in our Sun 3.0 compilers here at USC, ANY auto variable over 16k-bytes in size gets lunched on the second recursive entry. It took me 2 weeks and head bashing with the also buggie dbxtool to figure this one out. By breaking things up to <16k-bytes and using static, the code zooms!) -Mitch
mat@mtx5a.COM (m.terribile) (07/06/87)
> >>> There it is in a nutshell, you really don't need the * unless the function > >>> is declared int (**func)();, then you have pointer to pointer to a fun > >>> tion returning an integer. > > > >True ususally you want to pass the address of a strucuture. But what if > >you change the values of the structure in the function, and DON'T want > >to know about the changes after returning from the function???? > > Maybe I am not too familiar with the BIG frame architectures, but I am > somewhat familiar with items of the Sun/uVaxII genre on down. The issue > actually boils down to efficiency of structures and the simple fact is: > > Operations on static variables are ALWAYS faster than operations on auto > variables. No it does not, and no they are not. It does not boil down to that because the question of *what* you are pssing, and with what semantics, will not go away just because you want it to. And no, static references are not always cheaper. On the 68000, a reference to a something at a fixed address requires 2 to 4 bytes more memory and takes 2 to 4 extra clock cycles than a reference relative to an address register. > ... If you insist upon doing big structs as "auto" (stack) variables, > then there is probably not much difference in speed - both passing a > structure on the stack and copying to a local "auto" are slow. You do what you need to to get the semantics you need. If you don't need it, don't do it. > ... Secondly, MANY C compilers still do not support pushing anything other > than simple arguments on the stack. Pushing whole structures is NOT > portable in my book. Refusing to use an enhancement that became available years ago and has become as near to standard as anything else in the language is a disservice to yourself and to the people who worked to create the enhancement. > As it turns out, almost ALL efficient C compilers handle static memory > allocation much better than stack, too. So, you are not saving any REAL > memory, although swap decreases. (Use of static is REQUIRED in our Sun 3.0 > compilers here at USC, ANY auto variable over 16k-bytes in size gets lunched > on the second recursive entry. *THIS* is a nonstandard compiler bug. > It took me 2 weeks and head bashing with the also buggie dbxtool to figure > this one out. By breaking things up to <16k-bytes and using static, the > code zooms!) Arguing from bugs through bugs what can you expect except misfeatures? -- from Mole End Mark Terribile (scrape .. dig ) mtx5b!mat (Please mail to mtx5b!mat, NOT mtx5a! mat, or to mtx5a!mtx5b!mat) (mtx5b!mole-end!mat will also reach me) ,.. .,, ,,, ..,***_*.