tps@sdchem.UUCP (Tom Stockfisch) (09/11/86)
I want to pass a pointer to function returning "bool" to a function, but lint says I'm not doing it right. I think I am, aren't I? Sample code follows with messages from lint inserted. Is this a bug? typedef enum { FALSE = 0, TRUE = 1 } bool; bool truth(); void f(), g(); main() { /*###8 [lint] f arg. 1 used inconsistently testbool.c(14) :: testbool.c(8)%%%*/ f( truth ); } void f( ft ) bool (*ft)(); /*###14 [lint] f arg. 1 used inconsistently testbool.c(14) :: testbool.c(8)%%%*/ { /*###15 [lint] g arg. 1 used inconsistently testbool.c(21) :: testbool.c(15)%%%*/ g( ft ); } void g( gt ) /*###20 [lint] warning argument gt unused in function g%%%*/ bool (*gt)(); /*###21 [lint] g arg. 1 used inconsistently testbool.c(21) :: testbool.c(15)%%%*/ { } bool truth() { return TRUE; } -- -- Tom Stockfisch, UCSD Chemistry
guy@sun.uucp (Guy Harris) (09/12/86)
> I want to pass a > pointer to function returning "bool" > to a function, but lint says I'm not doing it right. I think I am, > aren't I? ... Is this a bug? Yes, and yes. PCC converts "enum"s into "char"s, "short"s, or "int"s at a fairly early stage in its processing. Unfortunately, this means "lint" does also. As such, "pointer to function returning enum" gets converted to "pointer to function returning char/short/int", which collides with the formal argument of "f". In this particular case, I tried it and it gave the errors listed; I changed the function pointer declarations to "int (*xx)()" and it passed. The fix is not to convert "enum"s in that fashion in "lint", and fix pass 2 to check that enum formal arguments match the actual arguments used. You can tell the parts of the language that were added later; the front end of PCC doesn't really handle them right. -- Guy Harris {ihnp4, decvax, seismo, decwrl, ...}!sun!guy guy@sun.com (or guy@sun.arpa)
karl@haddock (09/17/86)
sdchem!tps (Tom Stockfisch) writes: >I want to pass a pointer to function returning [enum bool] to a function, >but lint says I'm not doing it right. Cc and lint disagree about what "enum" really means. Lint calls it a new datatype, but cc thinks it's just a synonym for "int" in some contexts. Apparently the distinction is lost somewhere between lint pass 1 and pass 2. Yes, it's a bug. #if SOAPBOX I think cc should also treat them as distinct types. (The easy-going days of "everything is an int" are over, folks. Egad, now you have to *declare* functions, even if you're just passing the result to another function!) If you need an int context, you should cast the enum into an int. (Though switch(enum) should still work, provided all the case labels are enums.) I suppose an enum actually specifies an *ordered* set, so "++" and "--" are acceptable, as well as "+" and "-", but they work as with pointers: enum+int == enum, enum-enum == int. This proposal would make your "enum bool" less useful, but "typedef int bool" (which is what I always use) is just as good anyway. The only addition I'd like to make is to allow one to declare an array to be subscripted by an enum: "double foo[enum color]; foo[RED] = 1.0; ...". Such an array would *not* be subscriptable by int (though of course an integral expression could be cast into enum color and then used as a subscript). This would often obviate the need for a constant NCOLORS, and make the code more palatable to both cc and lint. A smart compiler could make a special case for sparse enums (enum color { RED=0, BLUE=100 }), as long as it's guaranteed that each valid instance of the enum type may be used as a subscript. The idea could be extended to allow any datatype, e.g. "int foo[char]" (which would subscript from -128 to 127 on a pdp11 or vax), but this is less useful. #endif /* SOAPBOX */ Karl W. Z. Heuer (ima!haddock!karl; karl@haddock.isc.com), The Walking Lint
rcd@nbires.UUCP (Dick Dunn) (09/18/86)
In article <86900054@haddock>, karl@haddock writes: > Cc and lint disagree about what "enum" really means. Lint calls it a new > datatype, but cc thinks it's just a synonym for "int" in some contexts. >... > #if SOAPBOX > I think cc should also treat them as distinct types. (The easy-going days > of "everything is an int" are over, folks... The problem goes a little deeper than this. Consider that if an enum is defined in a .h file, and that header file is used in two separate .c files, you have (by some annoyingly reasonable argument) two separate types! [Substitute canonical discussion of name equivalence vs structural equivalence of types here.] If lint were to make a name-equivalence type check, you couldn't use enums across modules. I suspect that it is not currently equipped to do the structural-equivalence test, although it's not that hard to do since there's no nesting or recursive structure in enums. But even then, explicit assignment of ordinals to enum elements, where the ordinals might be constant expressions (yes, bleah, but read on...) adds more worms to the can. Consider something silly like: ----------foo.h: typedef enum {a=XCONST, b, c} etype; ----------gleep.c #define YCONST 3 #define XCONST YCONST+YCONST #include "foo.h" etype xyzzy = b; ----------mumble.c #define YCONST 3 #define XCONST 2*YCONST #include "foo.h" extern etype xyzzy; Do the types of xyzzy in mumble.c and gleep.c match? They are provably both enums with the same type name and the same constituents with the same values, but... If you admit that name equivalence is inadequate (which I believe) but that this example carries structural equivalence too far (which I also believe, I think), then where do you draw the line? -- Dick Dunn {hao,ucbvax,allegra,seismo}!nbires!rcd (303)444-5710 x3086 ...Are you making this up as you go along?
notes@hcx1.UUCP (09/22/86)
On a somewhat related matter, I noticed the following: AT&T 5.2.2 source seems to accept the following, but Berkeley 4.2 & 4.3beta give a warning of inconsistent usage. struct st { int c ; } ; int func (b); int b; { } main() { struct st s; func (&s); } If 's' were a character array, however, AT&T would also complain. Dave Ray -- uucp: {ucf-cs|allegra}!novavax!hrshcx!hcx1!daver
guido@mcvax.uucp (Guido van Rossum) (09/23/86)
In article <572@opus.nbires.UUCP> rcd@nbires.UUCP (Dick Dunn) writes: >[example with enum {a= 3+3, b, c} in one file and enum {a= 2*3, b, c} >in another] > >If you admit that name equivalence is inadequate (which I believe) but that >this example carries structural equivalence too far (which I also believe, >I think), then where do you draw the line? In my eyes, in the example you give the two types are clearly structurally equivalent. After all, the two expressions have to be constant expressions, which is a well-defined term (in C!). I propose the following rule for enum equivalence: Two enumerated types are equivalent if they have the same 'tag' (or no tags), and define the same set of enumeration constants with the same associated value for each constant. (This will find even enum {a=2, b=1, c=0} and enum {c, b, a} equivalent!) By the way, I agree with the proposed ANSI standard which defines that enums are equivalent to ints! This is the only suitable way to do it *in C*, even though for any other language, to be designed newly, enums should be distinct types. I also agree with Lint checking enum equivalence -- but there should be a way to turn it off, since I believe that lint should not issue any errors (warnings are ok) for strictly ANSI-conforming C programs. -- Guido van Rossum, CWI, Amsterdam <guido@mcvax.uucp>
colin@vu-vlsi.UUCP (Colin Kelley) (09/23/86)
In article <103@hcx1.UUCP> notes@hcx1.UUCP writes: > >struct st { int c ; } ; >int func (b); > int b; >{ >} >main() >{ > struct st s; > func (&s); >} This is obviously wrong, since ints are not pointers! But what I thought you were going to try was main() { struct st s; func (s); } That is, call func() passing it the whole structure as if it were an int, since we all _know_ the structure just consists of one int anyway, right! PLEASE DON'T DO THIS!!! Of course it won't get by lint, but quite a few programmers wind up doing it because it works on so many machines. Well, it doesn't work at all on a Pyramid, where structures are passed differently than ints. Someone here got bitten by this attempting to port smp (a symbolic math package) to our Pyramid. The bozo programmer had declared a union containing all possible pointers, but then declared the formal parameter just as a pointer to an int. "What", you say, "commercial code which doesn't even pass lint?" That's what I said too! Yuck... -Colin Kelley ..{cbmvax,pyrnj,psuvax1}!vu-vlsi!colin
gbm@galbp.UUCP (Gary McKenney) (09/25/86)
> On a somewhat related matter, I noticed the following: > > AT&T 5.2.2 source seems to accept the following, but Berkeley 4.2 & 4.3beta > give a warning of inconsistent usage. > > struct st { int c ; } ; > int func (b); > int b; > { > } > main() > { > struct st s; > func (&s); > } > > If 's' were a character array, however, AT&T would also complain. > > Dave Ray -- uucp: {ucf-cs|allegra}!novavax!hrshcx!hcx1!daver Why don't you try: func (&s.c); I think this will be excepted to both and it still points to the beginning of the structure. gbm
gbm@galbp.UUCP (Gary McKenney) (09/25/86)
> > On a somewhat related matter, I noticed the following: > > > > AT&T 5.2.2 source seems to accept the following, but Berkeley 4.2 & 4.3beta > > give a warning of inconsistent usage. > > > > struct st { int c ; } ; > > int func (b); > > int b; > > { > > } > > main() > > { > > struct st s; > > func (&s); > > } > > > > If 's' were a character array, however, AT&T would also complain. > > > > Dave Ray -- uucp: {ucf-cs|allegra}!novavax!hrshcx!hcx1!daver > > Why don't you try: > > func (&s.c); > > I think this will be excepted to both and it still points to the beginning > of the structure. > > > gbm One additional comment (and error on my part). Your function is suppose to receive an integer, not a pointer to a structure. if you intend to receive an integer in func() then you should code... struct st { int c ; } ; int func (b); int b; { } main() { struct st s; func (s.c); } else if you intend to pass a pointer to the structure then you should code... struct st { int c ; } ; int func (b); char *b; { } main() { struct st s; func (&s.c); }
stuart@BMS-AT.UUCP (Stuart D. Gathman) (09/29/86)
In article <572@opus.nbires.UUCP>, rcd@nbires.UUCP (Dick Dunn) writes: > The problem goes a little deeper than this. Consider that if an enum is > defined in a .h file, and that header file is used in two separate .c > files, you have (by some annoyingly reasonable argument) two separate > types! [Substitute canonical discussion of name equivalence vs structural Did you ever wonder how lint handles _structures_ in .h files? It's really very simple: anything defined in the same file (even included files) with the same name is the same. The same logic works for enum. Note that identical structures defined in different files (i.e. a function returning a structure that is not defined with a .h file) are considered different types by lint. I like this because it encourages defining global structures in only one place (a header file). Lint keeps track of which file a definition is in with (I believe) the #line output of cpp. We have lint in Xenix and CTIX, two very different machines, and the above is true for both. I agree: cc should treat enum like structures. I especially wish that enum value names did not conflict with variable names. When using enum for switch cases or with enum variables, this use is obvious. Assigning enum values to int's would give an error. Is there ever a legitimate reason for doing so? (Why aren't you using an enum variable?) Note that you can still assign (or cast) an enum variable to an int. -- Stuart D. Gathman <..!seismo!{vrdxhq|dgis}!BMS-AT!stuart>
gnu@hoptoad.uucp (John Gilmore) (09/29/86)
I think the definitive word on this has been said already: Date: 8 Nov 1982 0216-PST (Monday) From: decwrl!decvax!harpo!npoiv!alice!research!dmr Subject: enums Newsgroups: net.lang.c There has been a lot of grousing about the uselessness of the enum type in C, most of it justified under the circumstances. The circumstances are that all versions of PCC that I know of are buggy in their treatment of this type. Enums were intended to be entirely equivalent to ints; just a way, really, of defining names for constants understood by the compiler and subject to the normal scope rules. There was a clear choice here: enums as utterly separate collections of atoms, more or less as in Pascal, or as ways of naming integers. I chose the latter after some waffling. Unfortunately, some of the waffle batter got mixed in with PCC and has stayed there. Dennis Ritchie -- John Gilmore {sun,ptsfa,lll-crg,ihnp4}!hoptoad!gnu jgilmore@lll-crg.arpa May the Source be with you!
chris@umcp-cs.UUCP (Chris Torek) (10/01/86)
>In article <572@opus.nbires.UUCP> rcd@nbires.UUCP (Dick Dunn) writes: >>The problem goes a little deeper than this. Consider that if an enum is >>defined in a .h file, and that header file is used in two separate .c >>files, you have (by some annoyingly reasonable argument) two separate >>types! [Substitute canonical discussion of name equivalence vs structural I do not agree, but I have always been a fan of structural equivalence. Anyway, onward: In article <226@BMS-AT.UUCP> stuart@BMS-AT.UUCP (Stuart D. Gathman) replies: >Did you ever wonder how lint handles _structures_ in .h files? It's really >very simple: anything defined in the same file (even included files) >with the same name is the same. The same logic works for enum. An interesting idea. >Note that identical structures defined in different files (i.e. >a function returning a structure that is not defined with a .h file) >are considered different types by lint. I like this because it >encourages defining global structures in only one place (a header file). Let us try an experiment. First: % more x.c y.c :::::::::::::: x.c :::::::::::::: struct s { int i; }; proc(p) struct s *p; { p->i = 1; } struct s func() { struct s temp; temp.i = 0; return (temp); } :::::::::::::: y.c :::::::::::::: struct s { int i; }; struct s func(); main() { struct s temp; temp = func(); proc(&temp); } % lint -h x.c y.c x.c: y.c: % Here the structures are described twice, but are identical in name and shape. Lint is happy with this. Now: % more x.c y.c :::::::::::::: x.c :::::::::::::: struct s2 { int i; }; proc(p) struct s2 *p; { p->i = 1; } struct s2 func() { struct s2 temp; temp.i = 0; return (temp); } :::::::::::::: y.c :::::::::::::: struct s { int i; }; struct s func(); main() { struct s temp; temp = func(); proc(&temp); } % lint -h x.c y.c x.c: y.c: % Clearly lint does not care about names. And one last change: % more x.c y.c % lint -h x.c y.c :::::::::::::: x.c :::::::::::::: struct s2 { int i, j; }; proc(p) struct s2 *p; { p->i = p->j = 1; } struct s2 func() { struct s2 temp; temp.i = temp.j = 0; return (temp); } :::::::::::::: y.c :::::::::::::: struct s { int i; }; struct s func(); main() { struct s temp; temp = func(); proc(&temp); } x.c: y.c: func value used inconsistently x.c(3) :: y.c(3) proc, arg. 1 used inconsistently x.c(2) :: y.c(3) % My (4.3BSD-beta) lint clearly uses structural conformability, not names or files. (As it happens, I prefer this behaviour.) Ideally, a new strongly-typed language (which would not then be C) should declare constraints on types, instead of having the compiler second guessing the programmer. For example, some enumerations might be ordered, others not: enum color { red ; green ; blue }; /* pred(green) undefined */ enum numbers { zero, one, two, many }; /* succ(two) = many */ If several operations are sensible, make sure all can be implemented ---though not necessarily by embedding them directly in the language. For now, C enumerated types are rather a mess, and I usually avoid them entirely. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu
stuart@BMS-AT.UUCP (Stuart D. Gathman) (10/04/86)
In article <3635@umcp-cs.UUCP>, chris@umcp-cs.UUCP (Chris Torek) writes: > x.c > :::::::::::::: > struct s { int i; }; > proc(p) struct s *p; { p->i = 1; } > struct s func() { struct s temp; temp.i = 0; return (temp); } > y.c > :::::::::::::: > struct s { int i; }; > struct s func(); > main() { struct s temp; temp = func(); proc(&temp); } > % lint -h x.c y.c > x.c: > y.c: Hmmmmm.... On trying this I see that only one of our two versions of lint uses the algorithm I described (the version with CTIX for the 68010). I still think that this example should generate an error. It is dangerous to have things defined in more than one place. The algorithm I described is safe. You can't define structures with the same name twice (in the same scope). Lint doesn't need to look at the actual structure definition, and can still flag code that should be flagged (like the above example). -- Stuart D. Gathman <..!seismo!{vrdxhq|dgis}!BMS-AT!stuart>