August 31st, 2003, 12:00 PM
It is normally considered bad practice to pass function calls, or expressions as parameters in C. This is a perfect example of why this is so.
Most professional coding standards are defined, not to restrict the programmers creative talent, but to prevent the unwary from getting into exactly this sort of problem - to avoid undefined behaviour.
Simply evaluate expressions and functions to temporary variables, and pass the variables. That avoids the problem, and is easier to debug.
August 31st, 2003, 12:37 PM
If it's considered bad practice, almost every programmer I've ever met is guilty. Using a function call as a parameter is fine. Making assumptions about the order of evaluation is not. Of course, if a compiler documents that it will always evaluate function arguments in a particular order then it can be relied upon, but it's not portable - perhaps not even to the next version of the same compiler.
By the way it's unspecified behaviour rather than undefined behaviour.
August 31st, 2003, 01:09 PM
bigbadbob i think you would make a very good contractual lawyer ;)
September 1st, 2003, 01:22 AM
I couldn't get to test the program until this morning. And then it took all day before I could get online.
First I tried it with MinGW gcc in the DOS window and I got the same reversed order.
Then I tried it with Visual C++ 1.52. I chose this version over v6 because the __pascal keyword needed in the next test is no longer supported.
Here's the code, followed by the output. The source code file serves as the test file, so we would expect the first three characters to be "#in":
void __pascal doit(int c1, int c2, int c3);
if ((fp = fopen("fgetc.c","rt")) == NULL)
printf("From Main: %c %c %c\n", fgetc(fp), fgetc(fp), fgetc(fp));
if ((fp = fopen("fgetc.c","rt")) == NULL)
doit(fgetc(fp), fgetc(fp), fgetc(fp));
if ((fp = fopen("fgetc.c","rt")) == NULL)
printf("A safe way:");
for (i=0; i<3; i++)
printf(" %c", fgetc(fp));
void __pascal doit(int c1, int c2, int c3)
printf("From pascal function: %c %c %c\n", c1,c2,c3);
So the compiler does not protect us against side-effects, resulting in the function calling convention dictating the order in which the characters are displayed. A safer way would be to either output each character before the next one is read (as in my "safe way" example) or to save them into a buffer in the order read for output later.
September 1st, 2003, 07:27 AM
I work as professional developer, heading teams of developers. Less experienced deveopers cost less money. In order to ensure code quality, a coding standard is imposed. The coding standard is intended to promote safe and robust coding practices that remain so through several years of code maintenance, re-use, and porting. This is a commercial consideration, in the long term it saves money.
In such a commercial environment, utilising knowledge of compiler dependent behaviour is normally unwise. That said, I once wrote code that assumed that a right-shift of a signed int did sign extension (for performance reasons - it was an interrupt routine). So sometimes certain practices can be justified, however I see no justification for the code posted in the original message.
September 1st, 2003, 02:10 PM
Coding standards are a good thing. A couple of years ago I was working for a very large company with many divisions spread across multiple sites. I was in responsible for a number of development teams and it became obvious that each team was working to a different C coding standard and all of them produced elsewhere. I tasked one of my senior developers with producing an in-house version. He did a reasonable job. A few months later someone from of the other divisions noticed the new standard on the company intranet and mentioned it in one of the company newsgroups. There followed much debate about the pros and cons of various items in the coding standard, with a great deal of religious heat generated.
The point I'm making is that there's no absolute consensus on what should or shouldn't be in a coding standard. Another name for a coding standard is a style guide, and therein lies a clue to the problem, it's about style. And it's almost impossible to get a large number of talented programmers to agree on style.
If it works for you and your teams in your environment to avoid using function calls as parameters then that's great. But some other places might consider that an unnecessary constraint (and others might agree with you). Each to their own. I'm not knocking coding standards, nor your own coding standard, but a consensus is difficult to achieve.
I agree with you. That said, the code posted is standard conforming. But it's not portable.
September 1st, 2003, 04:44 PM
That is a common misconception, a distinction must be made; a style guide is not a coding standard (although it may form part of one, but in my opinion they are better kept separate). While a style guide is intended to aid readability and clarity by imposing consistency, a coding standard legislates what parts of a language may be used, and how. The aim of a coding standard, by this definition, is to avoid language behaviour that either may differ between compilers, is ill defined by the standard (or undefined), or is commonly misused or misunderstood by practitioners (this case falls into the first and last category).
I agree that style guides cause religious argument, and are often unhelpful. The guide I produced is flexible, comprises mainly of recommendations rather than absolute directives, legislating against only those practices that are particularly perverse (such as over decorated comment blocks). In most cases, a directive is backed up by justification, and where possible I give acceptable alternatives. The reference for much of this work was Code Complete by Steve McConnell (Microsoft Press), and while even I disagree with some of his ideas, it is well worth looking at (and is superbly written).
A coding standard on the other hand is a more technical document, and few 'in-house' standards are adequate (I've written one of those too, but I know it is inadequate). For embedded systems (which is what I specialise in, and where software reliability is critical), there is a standard from The Motor Industry Software Reliability Association called MISRA C. MISRA C is now becoming more widely accepted outside of its original domain. It is defiantly not a style guide. Unfortunately you have to pay for it if you want to see the whole thing, but to give you an idea, there is an extract at http://www.misra.org.uk/graphics/miscprev.pdf. Some of MISRA C is probably only necessary in embedded or safety critical systems, but its philosophy, and much of its content is applicable to desktop applications as well (if all code were written like it were for a safety critical system, we'd have better quality software ... but pay much more). Unfortunately there is not yet a similar standard for C++, though a lot of MISRA C is of course applicable to C++.
The important thing to understand about MISRA C and all coding standards that fit the definition I gave earlier, is that they are enforceable by automated rule checking (so there can be no slacking, or argument!). PC-Lint by Gimpel Software for example can check code against MISRA rules (http://www.gimpel.com/html/misra.htm). Using such a tool, may mean that you need not buy the MISRA C standard; although you'd have to blindly follow the rules without the detailed justification!. After a while, when you've cleared the sevaral thousand warnings your old code generated, you'll naturally code in a manner that passes the checks, and quality improves.
Style guides are less important to good software; readability of unfamiliar code can be enhanced by syntax highlighting editors, and such editors are often capable or re-formatting the code to a preferred style. I cirrently use CodeWright for this, but actually prefer Visual SlickEdit. There are also standalone tools for formatting code, and these generally have more flexible options, but take some setting up if they are to be used to enforce standards compliance. Also you can make a rod for your own back with a style guide, since productivity can be enhanced by re-using non-conforming legacy code, or open source code, where you take what you can get.
Last edited by clifford; September 1st, 2003 at 05:00 PM.