RE: /usr/src/ed/bin/re.c:99

2002-11-06 Thread John Baldwin

On 06-Nov-2002 Marc Olzheim wrote:
 ..
 if ((nd = parse_char_class(++nd)) == NULL) {
 ..
 
 Hmmm... is this legal ?
 
 http://www.eskimo.com/~scs/C-faq/q3.1.html seems to tell otherwise...

If it were nd++, yes.  However, it is ++nd, thus, the increment
happens first, then the call to parse_char_class(), then the assignment
to nd.  It might be clearer to rewrite this like so however:

  if ((nd = parse_char_class(nd + 1)) == NULL) {

Since that is effectively what it is doing.

-- 

John Baldwin [EMAIL PROTECTED]http://www.FreeBSD.org/~jhb/
Power Users Use the Power to Serve!  -  http://www.FreeBSD.org/

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-hackers in the body of the message



Re: /usr/src/ed/bin/re.c:99

2002-11-06 Thread Peter Pentchev
On Wed, Nov 06, 2002 at 05:46:53PM +0100, Marc Olzheim wrote:
 ..
 if ((nd = parse_char_class(++nd)) == NULL) {
 ..
 
 Hmmm... is this legal ?
 
 http://www.eskimo.com/~scs/C-faq/q3.1.html seems to tell otherwise...

In this particular case, the value of 'nd' is not *used* anywhere in the
expression.  The fact that 'nd' is *assigned to* is not influenced in
any way by the change of its value.

It is absolutely certain that the compiler will put the code calculating
the value of the argument to parse_char_class() before the code actually
invoking parse_char_class(), and that it will also place the code
invoking parse_char_class() before the code which assigns the return
value to 'nd'.. thus, it is absolutely certain that 'nd' will be
assigned the correct value.

Once again: the main reason why q3.1 is not relevant here is the fact
that q3.1 deals with expressions where the value of 'nd' is used; here,
the left side of the assignment does not 'use' the value, it *changes*
it :)

Hope that helps.

G'luck,
Peter

-- 
Peter Pentchev  [EMAIL PROTECTED][EMAIL PROTECTED]
PGP key:http://people.FreeBSD.org/~roam/roam.key.asc
Key fingerprint FDBA FD79 C26F 3C51 C95E  DF9E ED18 B68D 1619 4553
I've heard that this sentence is a rumor.



msg37844/pgp0.pgp
Description: PGP signature


Re: RE: /usr/src/ed/bin/re.c:99

2002-11-06 Thread Erik Trulsson
On Wed, Nov 06, 2002 at 11:54:17AM -0500, John Baldwin wrote:
 
 On 06-Nov-2002 Marc Olzheim wrote:
  ..
  if ((nd = parse_char_class(++nd)) == NULL) {
  ..
  
  Hmmm... is this legal ?
  
  http://www.eskimo.com/~scs/C-faq/q3.1.html seems to tell otherwise...
 
 If it were nd++, yes.  However, it is ++nd, thus, the increment
 happens first, then the call to parse_char_class(), then the assignment
 to nd.  It might be clearer to rewrite this like so however:

In this regard nd++ and ++nd are completely equivalent. If parse_char_class
is a function (and not a macro) I think the expression might be legal
anyway since there is a sequence point after evaluating the arguments for
a function call and making the call. 
If, OTOH, parse_char_class is a macro then the above expression is
definitely not legal.
(It is not legal to modify an object more than once without a sequence
point in between.)


 
   if ((nd = parse_char_class(nd + 1)) == NULL) {
 
 Since that is effectively what it is doing.

Yes, that would be clearer and definitely legal.


-- 
Insert your favourite quote here.
Erik Trulsson
[EMAIL PROTECTED]


To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-hackers in the body of the message



Re: /usr/src/ed/bin/re.c:99

2002-11-06 Thread Marc Olzheim
 If it were nd++, yes.  However, it is ++nd, thus, the increment
 happens first, then the call to parse_char_class(), then the assignment
 to nd.

Ah right, sorry, my mistake...

Zlo

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-hackers in the body of the message



Re: /usr/src/ed/bin/re.c:99

2002-11-06 Thread Jordan K Hubbard
It's legal, though one would have to know what the author was thinking 
(or at least read the surrounding code) before stating that it's also 
correct.

It's legal because, unlike the example given in that FAQ entry you 
referenced, there's an implicit ordering in the expression that even 
the most aggressive compiler optimizer couldn't change.  In order for 
the value of parse_char_class() to be returned, its arguments must 
obviously be evaluated first and that means that ++nd will always occur 
before the assignment operator.

Stylistically, of course, it's ugly as hell and would be dinged by any 
CS professor grading this as homework.  Is nd a local variable?   If 
so, why didn't the author simply pass nd + 1 as the argument since 
the extra assignment from the unary operator is essentially wasted 
cycles?  Or is nd a global variable also referenced from within 
parse_char_class(), thus requiring the use of the ++ operator and if 
so, then why didn't parse_char_class() simply side-effect the global 
rather than forcing a re-assignment from within the parent function?  
Indeed, why is nd a global at all?  These and other questions are left 
as an exercise for the reader. :-)

- Jordan

On Wednesday, November 6, 2002, at 08:46 AM, Marc Olzheim wrote:

..
if ((nd = parse_char_class(++nd)) == NULL) {
..

Hmmm... is this legal ?

http://www.eskimo.com/~scs/C-faq/q3.1.html seems to tell otherwise...

Zlo

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-hackers in the body of the message


--
Jordan K. Hubbard
Engineering Manager, BSD technology group
Apple Computer


To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-hackers in the body of the message



Re: /usr/src/ed/bin/re.c:99

2002-11-06 Thread Terry Lambert
Marc Olzheim wrote:
 ..
 if ((nd = parse_char_class(++nd)) == NULL) {
 ..
 
 Hmmm... is this legal ?
 
 http://www.eskimo.com/~scs/C-faq/q3.1.html seems to tell otherwise...

The FAQ entry you reference has nothing to say about this at
all... it has to do with whether the *location* of the lvalue
is evaluate before or after a non-parenthetical post increment:

a[i] = i++;

That's totally different than:

if ((nd = parse_char_class(++nd)) == NULL) {

Whis is really:

nd = parse_char_class(++nd);
if (nd == NULL) {


Where the value has to be evaluated before the function is called
to obtain the rvalue to assign the lvalue, and the increment is a
preincrement.

Consider that the location of the lvalue 'nd' is not changed by
the value of the increment, whether it be pre- or post-.

There was a problem, at one point in time, with:

register value = function(register value);

in the Berkeley Portable C compiler; this is irrelevent for two
reasons:

1)  FreeBSD uses the GNU C compiler, which does not have
a problem with this construct

2)  The preincremenet would ensure that the bug was not
triggered; a common way of working around the bug was:

register value++;
register value--;
register value = function(register value);

FWIW, the bug in question is called the Berkeley pop order bug,
and existed on all Berkeley Portable C compiler derived compilers,
including the Sun C compiler on SunOS 4.x, and, potentially later
Sun operating systems.  The specific problem is that the register
was pushed for the call, and then popped after the call -- after
the assign, instead of before the assign.

This was particularly a problem in the X Widgets in the Motif 1.x
implementations, which would not run very well on SunOS, until
the code was manually rewritten (either to force the use of an
auto variable, since it's a register pop-order problem, or to do
the increment and decrement).

People who want their code to be portable avoid the construct:

x = function(x);

if there's any danger at all that 'x' will be promoted to a
register, and/or they expect their code to ever be compiled on
a Berkeley Portable C compiler derived compiler.

Most people don't actually care about portable code these days;
as long as their code runs on Linux, it doesn't have to run
elsewhere.

There are similarly non-portable constructs, which are generally
ignored by poor programmers; for example, the non-zeroing of a
sockaddr_in structures before calling socket(2), which cause
portability problems.  Also use of non-functional unit scoped
variable declarations in statement blocks, particularly registers,
would result in register overwrites in Lattice C compiler (which
is still sold under another name, these days).  Unions and bit
fields are also generally non-portable.  Unaligned structure
elements can cause access faults on some hardware (particularly
Alpha, but also 486+, if you set the right bit into the control
register).

Not having a space in the right place around parenthesis does not
work on some compilers; the FreeBSD style(9) actually insists that
the code not be fortable to some compilers (e.g. where the token
compare is agains while( instead of while, the insistance on
a space before the parenthesis ensures the code will not compile,
or the use of the template member operator :: not having a space
before it will fail to compile properly in the GNU C++ compiler,
prior to version 2.95, etc.).

In any case, your fears are unfounded, for the most part, since
the FAQ entry you are referencing is not analogous to the construct
you are trying to apply it to, anyway, and the FAQ fails to deal
with many of these portability issues, too, since it assumes that
the compiler is to spec..

-- Terry

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-hackers in the body of the message



Re: /usr/src/ed/bin/re.c:99

2002-11-06 Thread Marc Olzheim
[snip interesting piece of compiler history]

 In any case, your fears are unfounded, for the most part, since
 the FAQ entry you are referencing is not analogous to the construct
 you are trying to apply it to, anyway, and the FAQ fails to deal
 with many of these portability issues, too, since it assumes that
 the compiler is to spec..

If not in this FAQ, where else are things like this documented ? There
are also porgrammers who _do_ want to do it the portable/right way, but
if the documentation is nowhere to be found...

Any pointers ?

Thanks for the info,

Zlo

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-hackers in the body of the message



Re: /usr/src/ed/bin/re.c:99

2002-11-06 Thread Terry Lambert
Marc Olzheim wrote:
  In any case, your fears are unfounded, for the most part, since
  the FAQ entry you are referencing is not analogous to the construct
  you are trying to apply it to, anyway, and the FAQ fails to deal
  with many of these portability issues, too, since it assumes that
  the compiler is to spec..
 
 If not in this FAQ, where else are things like this documented ? There
 are also porgrammers who _do_ want to do it the portable/right way, but
 if the documentation is nowhere to be found...
 
 Any pointers ?
 
 Thanks for the info,

It's generally not well documented, except in the minds of people
who have had to deal with porting software to many platforms, over
time.  Really, you are unlikely to need these skills, since unless
you are working for a software vendor that has to run on what your
customers have available, you won't encounter most of the issues
(not really a problem, since no one writes for more than one OS these
days).

At one point in time, I wrote a small book called C for Race Car
Drivers (it was a good title at the time), that tried to teach you
how to code for speed (things like using for(;;) instead of
while(1) to avoid the extra compare inside the loop, etc.), and
for speed of porting to different UNIX platforms (do not use
structure assignments, do not use unions, do not use bit fields, do
not assume the sign of char, where to use the register keyword,
etc.).

Optimizing compilers killed most of the utility of the book, which
was mostly about how to write C source code so that the compilers
on these 40 platforms won't make a mistake, and so that the assembly
code that's emitted is fast.

If you are really interested in boundary conditions, ou would do
well to get access to some rather different compilers, and compile
up a lot of software, and see what doesn't compile, as well as what
breaks outright.

I don't know of any tools that will, for example, take the reference
implementation for SLPv2, as written by Sun, and complain sockaddr_in
used without bzero/memset, or take the ACAP source code and complain
use of '::' construct without guard spaces will not compile in GCC
prior to version 2.9.5, or Space between 'while' and '(' will not
compile on Wizard C on CTOS and BTOS platforms, or Declaration of
stack variable 'foo' in statement block not at top of function may
scribble on registers in SAS (Lattice) C compiler, or the OpenSSL
engine code and complain Use of array index instead of pointer for
descriptor entry references costs 48 out of 232 instructions in the
common case, please recode, etc., if that's what you're asking.

If you are just starting out, it's worthwhile to learn assembly
language, and spend some time figuring out what assembly language
will be emitted for certain types of source code: if a high level
language user knows what their code is going to do, they will be
able to write much better code.

-- Terry

To Unsubscribe: send mail to [EMAIL PROTECTED]
with unsubscribe freebsd-hackers in the body of the message