RE: /usr/src/ed/bin/re.c:99
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
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
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
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
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
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
[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
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