Possibilities of Return (with parameters???)

N

noe

Hello, I'm writing a file system filter driver and I've found in an example
this sentence:

if (VALID_FAST_IO_DISPATCH_HANDLER( fastIoDispatch, FastIoRead )) {

return (fastIoDispatch->FastIoRead)(
FileObject,
FileOffset,
Length,
Wait,
LockKey,
Buffer,
IoStatus,
nextDeviceObject );
}
 
J

Joona I Palaste

noe said:
Hello, I'm writing a file system filter driver and I've found in an example
this sentence:
if (VALID_FAST_IO_DISPATCH_HANDLER( fastIoDispatch, FastIoRead )) {
return (fastIoDispatch->FastIoRead)(
FileObject,
FileOffset,
Length,
Wait,
LockKey,
Buffer,
IoStatus,
nextDeviceObject );
}
Thanks in advance.

It's a function call in a return statement. It's equivalent to:

TYPE tmp = (fastIoDispatch->FastIoRead)(
FileObject, FileOffset, Length, Wait, LockKey, Buffer, IoStatus,
nextDeviceObject);
return tmp;

where TYPE is the appropriate return type of the function.

The function itself that is called is not named here - instead it is
pointed to by the pointer in (fastIoDispatch->FastIoRead). It is assumed
that it takes so many parameters.

--
/-- Joona Palaste ([email protected]) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"Outside of a dog, a book is a man's best friend. Inside a dog, it's too dark
to read anyway."
- Groucho Marx
 
L

Leor Zolman

Hello, I'm writing a file system filter driver and I've found in an example
this sentence:
[snip]

I've replied to your identical post on comp.lang.c++. Please do not
multi-post; if you /must/ post to multiple groups (and there's seldom good
reason to do so), at least "cross-post" by including all the groups in your
To: list at once.
Thanks,
-leor
 
E

Emmanuel Delahaye

noe said:
Hello, I'm writing a file system filter driver and I've found in an example
this sentence:

if (VALID_FAST_IO_DISPATCH_HANDLER( fastIoDispatch, FastIoRead )) {

return (fastIoDispatch->FastIoRead)(
FileObject,
FileOffset,
Length,
Wait,
LockKey,
Buffer,
IoStatus,
nextDeviceObject );
}

Yes, 'fastIoDispatch->FastIoRead' is a pointer to a function.
 
G

Guillaume

It's a function call in a return statement.

Yep. The parentheses around fastIoDispatch->FastIoRead are totally
useless though (and make it hard to read).

return fastIoDispatch->FastIoRead(...)

is much better.
 
L

Leor Zolman

I thought about this too, but was unsure about the precedence of the ->
and () operators.

<OT>
I've been trying to figure out if you (Joona) are a C++ programmer or not
by your posting history, and I'm guessing you're not (or at least, you
don't post about C++.). If you neither know C++ nor wish to hear about it,
I apologize in advance for what I'm about to say. Otherwise, here's an
easy way to remember about the precedence issue you mention above: Think
about calls to C++ member functions through pointers-to-objects:
p -> memfun(args);

-leor
</OT>
 
J

Joona I Palaste

<OT>
I've been trying to figure out if you (Joona) are a C++ programmer or not
by your posting history, and I'm guessing you're not (or at least, you
don't post about C++.). If you neither know C++ nor wish to hear about it,
I apologize in advance for what I'm about to say. Otherwise, here's an
easy way to remember about the precedence issue you mention above: Think
about calls to C++ member functions through pointers-to-objects:
p -> memfun(args);
-leor
</OT>

Nope, I'm not a C++ programmer. I'm a Java programmer first and a C
programmer second. I have no experience of C++ whatsoever. Therefore
your example does little to help me visualise the situation.
 
E

Eric Sosman

Joona said:
I thought about this too, but was unsure about the precedence of the ->
and () operators.

Some of C's operator precedences are downright screwy, and
I confess to some confusion even after two and a half decades'
experience with the language. (It may be that my experience
with other languages and their saner precedence rules makes it
difficult to recall which languages have which oddities; I've
become universally incompetent!)

However, this particular case is easy to figure out even if
you can't rely on memorization. Faced with p->f(x) you might
wonder whether it means (p->f)(x) or p->(f(x)). But look at
that second possibility: What meaning could it possibly have?
The thing that follows p-> must be the *name* of an element of
the *p struct (or union), and there's no way f(x) can return such
a thing. Only the first arrangement makes sense, so C understands
the "ambiguous" p->f(x) as (p->f)(x).

(Of course, one mustn't push such arguments too far. The
classic example is x-----y, which only makes sense if read as
(x--)-(--y). However, C understands it as ((x--)--)-y, which
is invalid and elicits a complaint.)
 
J

Joona I Palaste

Some of C's operator precedences are downright screwy, and
I confess to some confusion even after two and a half decades'
experience with the language. (It may be that my experience
with other languages and their saner precedence rules makes it
difficult to recall which languages have which oddities; I've
become universally incompetent!)
However, this particular case is easy to figure out even if
you can't rely on memorization. Faced with p->f(x) you might
wonder whether it means (p->f)(x) or p->(f(x)). But look at
that second possibility: What meaning could it possibly have?
The thing that follows p-> must be the *name* of an element of
the *p struct (or union), and there's no way f(x) can return such
a thing. Only the first arrangement makes sense, so C understands
the "ambiguous" p->f(x) as (p->f)(x).
(Of course, one mustn't push such arguments too far. The
classic example is x-----y, which only makes sense if read as
(x--)-(--y). However, C understands it as ((x--)--)-y, which
is invalid and elicits a complaint.)

Yes. I think C's token scanning uses the "maximal munch" principle: try
to scan the longest possible token from the characters remaining in the
stream.
A better (for humans) suited scanning algorithm would first scan all
the possibilities, then ask the parser (whose job it is to build syntax
trees out of the token stream) which makes the most sense, and use that.
However, compared to "maximal munch", it's difficult to implement and a
horrible lot slower.

--
/-- Joona Palaste ([email protected]) ------------- Finland --------\
\-- http://www.helsinki.fi/~palaste --------------------- rules! --------/
"Outside of a dog, a book is a man's best friend. Inside a dog, it's too dark
to read anyway."
- Groucho Marx
 
S

Sam Dennis

Joona said:
I was unsure about the precedence of the -> and () operators.

The same and, the real issue, left to right associative, as they
obviously must be.
 
L

Leor Zolman

Some of C's operator precedences are downright screwy, and
I confess to some confusion even after two and a half decades'
experience with the language.

After 25 years of dealing with C operator precedence, and 15 years of
teaching about it, this is how I distill the precedence table to what I
think are the bare essentials:

For binary operators:

0. Selection/flow control have highest precedence (. -> () [] )

1. My Dear Aunt Sally is next

2. Assignment is very, very low (only the "lowly" comma operator is lower)

3. All binary operators associate L-to-R, except assignment

Unary operators:

1. Very high precedence (beaten only by selection/flow control above) and
R-to-L associative (or, alternatively, postfix has higher precedence)



Those are the things worth memorizing, but I never make students memorize
anything about the precedence table (it is always available open-book,
unless I just post it up somewhere in the room.)

Any code that cannot be /clearly/ resolved by one of the above rules should
be explicitly parenthesized, whether it needs to or not. And sometimes even
code that /can/ be, should be parenthesized (strange combinations of My
Dear Aunt Sally subexpressions, for example).

I posit that well-written code should never force someone who has learned
the above rules to have to go scrambling for a precedence table.
-leor
 
M

Martin Dickopp

Leor Zolman said:
After 25 years of dealing with C operator precedence, and 15 years of
teaching about it, this is how I distill the precedence table to what I
think are the bare essentials:

For binary operators:

0. Selection/flow control have highest precedence (. -> () [] )

1. My Dear Aunt Sally is next

2. Assignment is very, very low (only the "lowly" comma operator is lower)

3. All binary operators associate L-to-R, except assignment

Unary operators:

1. Very high precedence (beaten only by selection/flow control above) and
R-to-L associative (or, alternatively, postfix has higher precedence)

Interesting. My first rule is "postfix operators have highest
precedence, followed by prefix operators". This encompasses your
rule #0 for binary operators and rule #1 for unary operators.

Note that I count . and -> as postfix operators. Unlike "real" infix
operators, which allow an /expression/ on both sides, . and -> require
an /identifier/ on their right hand side. In a way, I think of the
expression `foo->bar' as an operand `foo' followed by the postfix
operator `->bar'.

FWIW, if I cannot remember something about operator precedence, I just
have to type "man cop" at my Unix command line prompt. :)

<shameless plug>
The "cop" manual page can be downloaded from my homepage:
http://www.zero-based.org/programming/cop.7
</shameless plug>

Martin
 
G

Guillaume

return fastIoDispatch->FastIoRead(...)
I thought about this too, but was unsure about the precedence of the ->
and () operators.

In this case, it doesn't even matter, since obviously () applies in both
cases to the 'FastIoRead' member, whether you use additional parentheses
or not.
 
L

Leor Zolman

Leor Zolman said:
After 25 years of dealing with C operator precedence, and 15 years of
teaching about it, this is how I distill the precedence table to what I
think are the bare essentials:

For binary operators:

0. Selection/flow control have highest precedence (. -> () [] )

1. My Dear Aunt Sally is next

2. Assignment is very, very low (only the "lowly" comma operator is lower)

3. All binary operators associate L-to-R, except assignment

Unary operators:

1. Very high precedence (beaten only by selection/flow control above) and
R-to-L associative (or, alternatively, postfix has higher precedence)

Interesting. My first rule is "postfix operators have highest
precedence, followed by prefix operators". This encompasses your
rule #0 for binary operators and rule #1 for unary operators.

Note that I count . and -> as postfix operators. Unlike "real" infix
operators, which allow an /expression/ on both sides, . and -> require
an /identifier/ on their right hand side. In a way, I think of the
expression `foo->bar' as an operand `foo' followed by the postfix
operator `->bar'.

That looks like it simplifies things a little, but it necessitates
characterization of operators in a way that is at odds with the K&R
precedence table. I'd prefer not to have to justify and explain that . and
-> are either unary, postfix or both. Especially since [] really /is/
binary, and () is...well, something other than unary ;-)
-leor
 
C

CBFalconer

Joona said:
.... snip ...

Yes. I think C's token scanning uses the "maximal munch" principle:
try to scan the longest possible token from the characters
remaining in the stream.
A better (for humans) suited scanning algorithm would first scan
all the possibilities, then ask the parser (whose job it is to
build syntax trees out of the token stream) which makes the most
sense, and use that. However, compared to "maximal munch", it's
difficult to implement and a horrible lot slower.

Forgetting C entirely for the moment, I consider that an input
scanner should be designed for one char. look ahead.
Unfortunately the C usage for long/float inputs violates this
requirement.
 
C

CBFalconer

Leor said:
Eric Sosman said:
Some of C's operator precedences are downright screwy, and
I confess to some confusion even after two and a half decades'
experience with the language.

After 25 years of dealing with C operator precedence, and 15
years of teaching about it, this is how I distill the precedence
table to what I think are the bare essentials:

For binary operators:

0. Selection/flow control have highest precedence (. -> () [] )
1. My Dear Aunt Sally is next
2. Assignment is very, very low (only the "lowly" comma operator
is lower)
3. All binary operators associate L-to-R, except assignment

Unary operators:

1. Very high precedence (beaten only by selection/flow control
above) and R-to-L associative (or, alternatively, postfix
has higher precedence)

Those are the things worth memorizing, but I never make students
memorize anything about the precedence table (it is always
available open-book, unless I just post it up somewhere in the
room.)

Any code that cannot be /clearly/ resolved by one of the above
rules should be explicitly parenthesized, whether it needs to or
not. And sometimes even code that /can/ be, should be
parenthesized (strange combinations of My Dear Aunt Sally
subexpressions, for example).

I posit that well-written code should never force someone who
has learned the above rules to have to go scrambling for a
precedence table.

Very nice. You have regularized my generic mumblings about "use
more parentheses" into a very usable (and teachable) set of
rules. Your rules could also be incorporated into a lint or
lint-like utility to scan source for possibly confused statements.
 
M

Martin Dickopp

Leor Zolman said:
Leor Zolman said:
After 25 years of dealing with C operator precedence, and 15 years of
teaching about it, this is how I distill the precedence table to what I
think are the bare essentials:

For binary operators:

0. Selection/flow control have highest precedence (. -> () [] )

1. My Dear Aunt Sally is next

2. Assignment is very, very low (only the "lowly" comma operator is lower)

3. All binary operators associate L-to-R, except assignment

Unary operators:

1. Very high precedence (beaten only by selection/flow control above) and
R-to-L associative (or, alternatively, postfix has higher precedence)

Interesting. My first rule is "postfix operators have highest
precedence, followed by prefix operators". This encompasses your
rule #0 for binary operators and rule #1 for unary operators.

Note that I count . and -> as postfix operators. Unlike "real" infix
operators, which allow an /expression/ on both sides, . and -> require
an /identifier/ on their right hand side. In a way, I think of the
expression `foo->bar' as an operand `foo' followed by the postfix
operator `->bar'.

That looks like it simplifies things a little, but it necessitates
characterization of operators in a way that is at odds with the K&R
precedence table. I'd prefer not to have to justify and explain that
. and -> are either unary, postfix or both.

I have explained (to students) that my view is an alternative one
which I personally prefer to memorize things. So far, students have
taken this quite well, but then again, you have /much/ longer teaching
experience than I have, so YMMV.
Especially since [] really /is/ binary,

Yes, it's binary postfix. The ] character is the /real/ operator;
the [ character is merely needed to separate the operands. ;-)
and () is...well, something other than unary ;-)

....unless the function is called with no arguments, in which case () is
clearly unary postfix. ;-)

Martin
 
D

Dan Pop

In said:
I thought about this too, but was unsure about the precedence of the ->
and () operators.

Which shows that, at least for some people, the parenthesised version
is easier to read, as it removes *any* doubts WRT its correct parsing.

Dan
 
D

Dan Pop

In said:
Some of C's operator precedences are downright screwy, and
I confess to some confusion even after two and a half decades'
experience with the language. (It may be that my experience
with other languages and their saner precedence rules makes it
difficult to recall which languages have which oddities; I've
become universally incompetent!)

However, this particular case is easy to figure out even if
you can't rely on memorization. Faced with p->f(x) you might
wonder whether it means (p->f)(x) or p->(f(x)). But look at
that second possibility: What meaning could it possibly have?
The thing that follows p-> must be the *name* of an element of
the *p struct (or union), and there's no way f(x) can return such
a thing. Only the first arrangement makes sense, so C understands
the "ambiguous" p->f(x) as (p->f)(x).

(Of course, one mustn't push such arguments too far. The
classic example is x-----y, which only makes sense if read as
(x--)-(--y). However, C understands it as ((x--)--)-y, which
is invalid and elicits a complaint.)

So, you're disproving your own argument: there is no a priori way to
know whether p->f(x) is the same as (p->f)(x) or an invalid program
construct requiring a diagnostic. A proper analysis, involving the
precedence and associativity of the two operators involved is *needed*.

OTOH, (p->f)(x) requires no such analysis, so it is, by definition, more
readable.

Dan
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,011
Latest member
AjaUqq1950

Latest Threads

Top