|
Home > Archive > Unix Programming > August 2005 > Difference between variables and functions
You are viewing an archived Text-only version of the thread.
To view this thread in it's original format and/or if you want to reply to
this thread please [click here]
| Author |
Difference between variables and functions
|
|
|
| Gcc doesn't seem to know the difference between variables and functions. In
the program:
#include <fcntl.h>
#include <unistd.h>
int main(void)
{
int read = 4;
int fd = open("lasix.ps", O_RDONLY);
char buf[900];
read = read( fd, buf, 1 );
return 0;
}
Gcc gives the error:
$ gcc-4.0 -W -Wall test.c
test.c: In function `main':
test.c:10: error: called object `read' is not a function
$ gcc-3.3 -W -Wall test.c
test.c: In function `main':
test.c:10: error: called object is not a function
"read" is not a reserved word, and gcc should be smart enough to parse
line 10 since variables can't end in a left parenthesis.
Is this really not valid C?
Thanks!
Gordon
| |
| Pascal Bourguignon 2005-08-28, 5:50 pm |
| <gordon@nospam.edu> writes:
> Gcc doesn't seem to know the difference between variables and functions. In
> the program:
> read = read( fd, buf, 1 );
> Gcc gives the error:
> Is this really not valid C?
Yes. What did you believe? C is a mere assembler, not a high level
language like Common Lisp!
--
__Pascal Bourguignon__ http://www.informatimago.com/
This is a signature virus. Add me to your signature and help me to live
| |
| Rich Teer 2005-08-28, 5:50 pm |
| On Sun, 28 Aug 2005 gordon@nospam.edu wrote:
> Is this really not valid C?
It's valid C*, but very poor programming technique.
* Given that read() isn't specified by ISO C.
--
Rich Teer, SCNA, SCSA, OpenSolaris CAB member
President,
Rite Online Inc.
Voice: +1 (250) 979-1638
URL: http://www.rite-group.com/rich
| |
| Gordon Burditt 2005-08-28, 5:50 pm |
| >Gcc doesn't seem to know the difference between variables and functions. In
A variable of type pointer-to-function is a variable but it can be
used as the variable 'read' is used in line 10 below (in both places)
assuming that it was declared with a suitable type in line 6.
>the program:
>
> #include <fcntl.h>
> #include <unistd.h>
>
> int main(void)
> {
> int read = 4; /* line 6 */
> int fd = open("lasix.ps", O_RDONLY);
> char buf[900];
>
> read = read( fd, buf, 1 ); /* line 10 */
>
> return 0;
> }
>
>Gcc gives the error:
>
>$ gcc-4.0 -W -Wall test.c
>test.c: In function `main':
>test.c:10: error: called object `read' is not a function
>
>$ gcc-3.3 -W -Wall test.c
>test.c: In function `main':
>test.c:10: error: called object is not a function
>"read" is not a reserved word, and gcc should be smart enough to parse
>line 10 since variables can't end in a left parenthesis.
Yes, it is perfectly allowed to have a variable of suitable type
followed by a left parenthesis.
>Is this really not valid C?
Yes, it is really not valid C.
Gordon L. Burditt
| |
| Ulrich Hobelmann 2005-08-28, 5:50 pm |
| gordon@nospam.edu wrote:
> Gcc doesn't seem to know the difference between variables and functions. In
> the program:
>
> #include <fcntl.h>
> #include <unistd.h>
>
> int main(void)
> {
> int read = 4;
> int fd = open("lasix.ps", O_RDONLY);
> char buf[900];
>
> read = read( fd, buf, 1 );
>
> return 0;
> }
>
> Gcc gives the error:
>
> $ gcc-4.0 -W -Wall test.c
> test.c: In function `main':
> test.c:10: error: called object `read' is not a function
Funny, to complain (with an error, not a warning!) that the variable
read is not a function, but not call the function instead (and just
issue a warning).
> "read" is not a reserved word, and gcc should be smart enough to parse
> line 10 since variables can't end in a left parenthesis.
I'd say it's a name conflict. C has a common namespace for functions
and variables, and since you declare read as an int, that shadows the
function definition from <unistd.h>.
But C has first class functions, so you can store functions in variables
and use them as parameters or return them from functions. So I'd say
that calling the int variable "read" with three parameters should be
valid C, just not meaningful.
> Is this really not valid C?
I think it should be valid. The gcc errors makes some sense, as you
init the variable to 4, which is probably not a valid function memory
address. But I think that's not at all what gcc is inferring. I didn't
know that mere type problems throw real errors in C; I usually only have
to deal with pointer cast warnings.
--
My ideal for the future is to develop a filesystem remote interface
(a la Plan 9) and then have it implemented across the Internet as
the standard rather than HTML. That would be ultimate cool.
Ken Thompson
| |
| Floyd L. Davidson 2005-08-28, 5:50 pm |
| Rich Teer <rich.teer@rite-group.com> wrote:
>On Sun, 28 Aug 2005 gordon@nospam.edu wrote:
>
>
>It's valid C*, but very poor programming technique.
>
>* Given that read() isn't specified by ISO C.
Calling a type int variable is "valid C"? ;-)
Whether read() is ISO C or not has little to do with it, because
the /library/ /symbol/ named "read" will not be linked unless it is
unresolved, which is not the case in the OP's code.
--
Floyd L. Davidson <http://www.apaflo.com/floyd_davidson>
Ukpeagvik (Barrow, Alaska) floyd@apaflo.com
| |
| Erik Max Francis 2005-08-28, 5:50 pm |
| Ulrich Hobelmann wrote:
> Funny, to complain (with an error, not a warning!) that the variable
> read is not a function, but not call the function instead (and just
> issue a warning).
It's giving an error because it _is_ an error; what he wrote is illegal.
Yes, the compiler could try to guess what he meant and hide the error,
but that often leads to far more problems. In this case he clearly
tried to do something illegal according to the C Standards and so the
compiler said so, indicating matter-of-factly what the problem was, and
refused to compile it. This is _good_ behavior, not funny behavior.
It's obvious to _you_ what he meant, because understood his intent and
could tell from the code sample that he meant to call the function named
read. But the compiler cannot do this, and so it shouldn't try, since
if it did it would make mistakes and confuse the programmer even
further. What if it wasn't a name conflict caused by a misunderstanding
of how the language worked, but rather a typo? In that case, second
guessing what the programmer meant and calling the function would be
exactly the _wrong_ thing to do.
It's illegal, it should compile, and it didn't. That's the way it's
supposed to work.
> But C has first class functions, so you can store functions in variables
> and use them as parameters or return them from functions. So I'd say
> that calling the int variable "read" with three parameters should be
> valid C, just not meaningful.
Having pointers to functions doesn't make them first class.
> I think it should be valid. The gcc errors makes some sense, as you
> init the variable to 4, which is probably not a valid function memory
> address. But I think that's not at all what gcc is inferring. I didn't
> know that mere type problems throw real errors in C; I usually only have
> to deal with pointer cast warnings.
It is not and has never been valid in C.
--
Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
If you are afraid of loneliness, do not marry.
-- Anton Chekhov
| |
| Erik Max Francis 2005-08-28, 5:50 pm |
| Rich Teer wrote:
> It's valid C*, but very poor programming technique.
>
> * Given that read() isn't specified by ISO C.
This doesn't really have much to do with ISO, since it would still be
illegal if it were a name conflict between a user-defined function and a
user-defined local variable.
--
Erik Max Francis && max@alcyone.com && http://www.alcyone.com/max/
San Jose, CA, USA && 37 20 N 121 53 W && AIM erikmaxfrancis
If you are afraid of loneliness, do not marry.
-- Anton Chekhov
| |
| Rich Teer 2005-08-28, 5:50 pm |
| On Sun, 28 Aug 2005, Floyd L. Davidson wrote:
> Rich Teer <rich.teer@rite-group.com> wrote:
>
> Calling a type int variable is "valid C"? ;-)
*sigh* A case of not typing what I was thinking. Note to self:
proof-read twice, post once. :-)
--
Rich Teer, SCNA, SCSA, OpenSolaris CAB member
President,
Rite Online Inc.
Voice: +1 (250) 979-1638
URL: http://www.rite-group.com/rich
| |
| Bryan Donlan 2005-08-28, 8:48 pm |
| Ulrich Hobelmann wrote:
> gordon@nospam.edu wrote:
>
> Funny, to complain (with an error, not a warning!) that the variable
> read is not a function, but not call the function instead (and just
> issue a warning).
>
>
> I'd say it's a name conflict. C has a common namespace for functions
> and variables, and since you declare read as an int, that shadows the
> function definition from <unistd.h>.
>
> But C has first class functions, so you can store functions in variables
> and use them as parameters or return them from functions. So I'd say
> that calling the int variable "read" with three parameters should be
> valid C, just not meaningful.
C does not have first class functions; not even close. It has function
pointers, but these are completely different from ints, and trying to call
an int is nonsensical.
>
> I think it should be valid. The gcc errors makes some sense, as you
> init the variable to 4, which is probably not a valid function memory
> address. But I think that's not at all what gcc is inferring. I didn't
> know that mere type problems throw real errors in C; I usually only have
> to deal with pointer cast warnings.
It is not valid C; the declaration of 'int read' hides the function
prototype of read in global scope.
--
λz.λi.i(i((λn.λm.λz.λi.nz(λq.mqi))((λn.λz.λi.n(nzi)i)(λz.λi.i(((λn.λz.λi.n
(nzi)i)(λz.λi.i(iz)))zi)))((λn.λz.λi.n(nzi)i)(λz.λi.i(iz)))zi))
| |
| Barry Margolin 2005-08-28, 8:48 pm |
| In article <3nem0nF15bjvU1@individual.net>,
Ulrich Hobelmann <u.hobelmann@web.de> wrote:
> But C has first class functions, so you can store functions in variables
> and use them as parameters or return them from functions. So I'd say
> that calling the int variable "read" with three parameters should be
> valid C, just not meaningful.
The only variables that can be used this way are those of type pointer
to function. Since the variable "read" is not of this type, it's not
valid to use it in a function call context.
--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
| |
| Ulrich Hobelmann 2005-08-29, 2:52 am |
| Erik Max Francis wrote:
> It's obvious to _you_ what he meant, because understood his intent and
> could tell from the code sample that he meant to call the function named
> read. But the compiler cannot do this, and so it shouldn't try, since
> if it did it would make mistakes and confuse the programmer even
> further.
I agree there.
> What if it wasn't a name conflict caused by a misunderstanding
> of how the language worked, but rather a typo? In that case, second
> guessing what the programmer meant and calling the function would be
> exactly the _wrong_ thing to do.
But he's calling a variable, so IMHO C should compile an indirect
function call there. The int variable read could have been casted from
a function pointer, in theory, and I don't think that gcc actually
noticed that it didn't. That's why I wonder why it doesn't warn and do it.
> It's illegal, it should compile, and it didn't. That's the way it's
> supposed to work.
But what's the concrete error? If the type of read were not int, but
function, it should compile. If it isn't, it should issue a warning,
like when I try to derefence a void *, or pass an int to a function that
expects a void *.
>
> Having pointers to functions doesn't make them first class.
How not? You can't create nameless functions in C, but that's about
all. I don't know if first-class struct initializers are C99, or just
GNU C, either. Lots of things are a bit awkward in C, but functions are
full values.
C doesn't have full *closures*, but you can emulate them (function +
context variable).
>
> It is not and has never been valid in C.
Hm, if you say so. ;)
--
My ideal for the future is to develop a filesystem remote interface
(a la Plan 9) and then have it implemented across the Internet as
the standard rather than HTML. That would be ultimate cool.
Ken Thompson
| |
| Ulrich Hobelmann 2005-08-29, 2:52 am |
| Barry Margolin wrote:
> In article <3nem0nF15bjvU1@individual.net>,
> Ulrich Hobelmann <u.hobelmann@web.de> wrote:
>
>
> The only variables that can be used this way are those of type pointer
> to function. Since the variable "read" is not of this type, it's not
> valid to use it in a function call context.
Wow, I've never experienced C being that anal about types (except when
it doesn't know the size of a struct that it needs for allocation). I
assumed that it's all just memory addresses underneath, with some loose
checking on top.
--
My ideal for the future is to develop a filesystem remote interface
(a la Plan 9) and then have it implemented across the Internet as
the standard rather than HTML. That would be ultimate cool.
Ken Thompson
| |
| Nils O. Selåsdal 2005-08-29, 7:50 am |
| gordon@nospam.edu wrote:
> Gcc doesn't seem to know the difference between variables and functions. In
> the program:
symbols are "resolved" from the innermost scope to the outermost.
You have declared read to be an int. The compiler correctly catches
the fact it isn't a function, yet you tried to call "read" as if it were
a function. They all live in the same namespace in C, so a compiler
doesn't know the difference between read the function and read the
int, at that point...
| |
| Eric Sosman 2005-08-29, 6:00 pm |
|
Ulrich Hobelmann wrote:
> Erik Max Francis wrote:
>
>
>
> I agree there.
>
>
>
>
> But he's calling a variable, so IMHO C should compile an indirect
> function call there.
Some other language, perhaps, but not C. Attempting
to call an `int' (or a `double' or a `struct gizmo') is a
constraint violation:
6.5.2.2 Function calls
Constraints
1 The expression that denotes the called function
shall have type pointer to function [...]
A diagnostic is required (5.1.1.3).
--
Eric.Sosman@sun.com
| |
| Bryan Donlan 2005-08-29, 6:00 pm |
| Ulrich Hobelmann wrote:
> Barry Margolin wrote:
>
> Wow, I've never experienced C being that anal about types (except when
> it doesn't know the size of a struct that it needs for allocation). I
> assumed that it's all just memory addresses underneath, with some loose
> checking on top.
>
Well, it is, this is the loose checking throwing up an error 
--
λz.λi.i(i((λn.λm.λz.λi.nz(λq.mqi))((λn.λz.λi.n(nzi)i)(λz.λi.i(((λn.λz.λi.n
(nzi)i)(λz.λi.i(iz)))zi)))((λn.λz.λi.n(nzi)i)(λz.λi.i(iz)))zi))
| |
| Brian Raiter 2005-08-29, 8:51 pm |
| >> What if it wasn't a name conflict caused by a misunderstanding of
>
> But he's calling a variable, so IMHO C should compile an indirect
> function call there.
Are you serious? A function's return value is part of its type. Should
the C compiler also take an educated guess as to the return type when
it magically casts this integer into a function pointer? And note that
we're ignoring the issue of the parameters for now, since C still
allows function parameters to go unspecified (though this is pretty
much deprecated).
If we assumed that the above issues were solved satisfactorily, then I
grant that it would be *possible* for an ANSI-compliant compiler to do
(since any attempt to use an integral value as a pointer is
automatically undefined behavior by the standard).
However, the odds are overwhelmingly that such a construction is a
typo, not intentional behavior, so I think it would be foolish for a
good compiler to accept such code silently. Far better to require the
user to explicitly put in a cast to a) indicate the type of the
parameters and return value, and b) show the compiler that this really
is what the programmer intended to do:
read = ((ssize_t (*)(int, void*, size_t))read)(fd, buf, 1);
I believe gcc will accept the above line. (Though of course I wouldn't
recommend running it.)
>
> But what's the concrete error?
Well, the short answer ANSI C standard does not permit you to use
integral values cast into pointer values. Any attempt to do so results
in undefined behavior, so the compiler is free to do whatever it wants
with your program. Many compilers choose to issue an error unless an
explicit cast is made. Not only does this make sense, but it also
frees the compiler from trying to deduce the correct pointer type from
the surrounding context.
b
| |
| Barry Margolin 2005-08-30, 2:56 am |
| In article <3nfsn0F1a6vtU2@individual.net>,
Ulrich Hobelmann <u.hobelmann@web.de> wrote:
> Barry Margolin wrote:
>
> Wow, I've never experienced C being that anal about types (except when
> it doesn't know the size of a struct that it needs for allocation). I
> assumed that it's all just memory addresses underneath, with some loose
> checking on top.
The analness is implementation-dependent. The language specification
says that calling a non-function has undefined consequences, which means
implementations can do anything. So some implementations with minimal
type checking will allow it through (and hopefully you'll get a
segmentation violation or something like that at runtime), while others
will do the additional checking and report the error at compile time.
Sounds like the OP was using one of the latter types of compilers.
In general, over the years C compilers have gotten a bit better at this
type of thing. In the early days of C, computers didn't have much
memory and the compilers were deliberately kept simple. Now disk and
memory are cheap, and bugs that could have been detected at compile time
can result in security holes, so it's more common to do as much checking
as the language allows.
--
Barry Margolin, barmar@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***
| |
| Keith Thompson 2005-08-30, 2:56 am |
| Ulrich Hobelmann <u.hobelmann@web.de> writes:
> Barry Margolin wrote:
>
> Wow, I've never experienced C being that anal about types (except when
> it doesn't know the size of a struct that it needs for allocation). I
> assumed that it's all just memory addresses underneath, with some
> loose checking on top.
No, C's type checking isn't nearly as loose as you seem to be assuming
it is.
For example, in standard C, integer types and pointer types are
distinct, and except for the oddity of using a literal 0 as a null
pointer constant, they are not interchangeable. Some compilers,
particularly older ones, may be looser about this, but as far as the
standard is concerned, nearly any attempt to use an integer value in a
pointer context or vice versa is a constraint violation, requiring a
diagnostic.
Also, distinct pointer types (other than void*) are not
interchangeable. Given:
int *iptr;
float *fptr;
the assignment
iptr = fptr
is a constraint violation.
The perception that C has loose type checking is probably based on
several things:
Numeric types are implicitly converted to each other fairly freely.
Arrays are implicitly converted to pointers in most contexts. (This
isn't realy loose type checking; the rules for doing this are
rigorously defined.)
Character types are integer types; thus
char c = 'x';
int x = c;
is legal.
A literal 0 can be used as a null pointer constant. (Integer literals
other than 0 cannot be directly used as pointer values.)
In a call to a function with no prototype, or to a function that takes
a variable number of arguments, much of the normal type checking is
not done. But the requirements are still nearly as strict; violating
them needn't be diagnosed, but it causes undefined behavior.
None of that comes anywhere near implying that you can call an
integer as if it were a function.
--
Keith Thompson (The_Other_Keith) kst-u@mib.org <http://www.ghoti.net/~kst>
San Diego Supercomputer Center <*> <http://users.sdsc.edu/~kst>
We must do something. This is something. Therefore, we must do this.
| |
| joe@invalid.address 2005-08-30, 2:56 am |
| Ulrich Hobelmann <u.hobelmann@web.de> writes:
> Wow, I've never experienced C being that anal about types (except
> when it doesn't know the size of a struct that it needs for
> allocation). I assumed that it's all just memory addresses
> underneath, with some loose checking on top.
The OP's code set an int to 4. Then it tried to call the value 4 as a
function, which would mean (I guess) that the compiler was expected to
generate code that would just jump to address 4 and start executing.
There have been several good responses based on the definition of
C. I'm just wondering why you think it would be a good thing for the
compiler to blissfully cast the number 4 to a pointer to function and
try to start executing code at that address?
I'm not an expert though, I'm just asking. The fact that it won't do
that seems more like reasonable than anal to me.
Joe
| |
| Ulrich Hobelmann 2005-08-30, 8:14 am |
| joe@invalid.address wrote:
> The OP's code set an int to 4. Then it tried to call the value 4 as a
> function, which would mean (I guess) that the compiler was expected to
> generate code that would just jump to address 4 and start executing.
>
> There have been several good responses based on the definition of
> C. I'm just wondering why you think it would be a good thing for the
> compiler to blissfully cast the number 4 to a pointer to function and
> try to start executing code at that address?
No, as Keith writes, I was under the impression that C had somewhat
loose type-checking, when often it doesn't. Thanks to you guys for
educating me!
> I'm not an expert though, I'm just asking. The fact that it won't do
> that seems more like reasonable than anal to me.
Sure, the call doesn't make sense. It was my wrong understanding of C's
type system that led me to expect that a call to "4" should be compiled ;)
--
My ideal for the future is to develop a filesystem remote interface
(a la Plan 9) and then have it implemented across the Internet as
the standard rather than HTML. That would be ultimate cool.
Ken Thompson
| |
| Eric Sosman 2005-08-30, 6:00 pm |
|
Barry Margolin wrote:
> In article <3nfsn0F1a6vtU2@individual.net>,
> Ulrich Hobelmann <u.hobelmann@web.de> wrote:
>
>
>
>
> The analness is implementation-dependent. The language specification
> says that calling a non-function has undefined consequences, which means
> implementations can do anything. So some implementations with minimal
> type checking will allow it through (and hopefully you'll get a
> segmentation violation or something like that at runtime), while others
> will do the additional checking and report the error at compile time.
> Sounds like the OP was using one of the latter types of compilers.
Attempting to call a non-function[*] is a constraint
violation that requires a diagnostic. Any compiler that
fails to produce the diagnostic does not conform to the
language definition. Or, to turn it around, all conforming
compilers are of "the latter type" and do the "additional"
checking.
[*] That is, attempting to apply the () function-call
operator to an expression whose type is not "pointer to
function." Calling a function pointer that has been set
to an invalid value is a different matter, and not the
subject of the O.P.'s question.
--
Eric.Sosman@sun.com
| |
| Wayne C. Morris 2005-08-30, 6:00 pm |
| In article <m37je4kky6.fsf@invalid.address>, joe@invalid.address wrote:
> Ulrich Hobelmann <u.hobelmann@web.de> writes:
>
>
> The OP's code set an int to 4. Then it tried to call the value 4 as a
> function, which would mean (I guess) that the compiler was expected to
> generate code that would just jump to address 4 and start executing.
>
Well, that's what his code tried to do, but that's not what he intended; he
thought he should be allowed to have both a function and a variable named
"read" in the same scope, and that the C compiler should be "smart enough"
to figure out from context which 'read' was being referenced. The OP
simply asked whether this really is invalid in C.
Ulrich thought the OP *wanted* to call a function at memory address 4,
resulting in this tangential discussion about whether C should let you
'call' an int variable without an explicit cast.
| |
| Ulrich Hobelmann 2005-08-30, 6:00 pm |
| Wayne C. Morris wrote:
> Well, that's what his code tried to do, but that's not what he intended; he
> thought he should be allowed to have both a function and a variable named
> "read" in the same scope, and that the C compiler should be "smart enough"
> to figure out from context which 'read' was being referenced. The OP
> simply asked whether this really is invalid in C.
>
> Ulrich thought the OP *wanted* to call a function at memory address 4,
No, I was just under the impression that C should compile that.
> resulting in this tangential discussion about whether C should let you
> 'call' an int variable without an explicit cast.
--
My ideal for the future is to develop a filesystem remote interface
(a la Plan 9) and then have it implemented across the Internet as
the standard rather than HTML. That would be ultimate cool.
Ken Thompson
|
|
|
|
|