Connecting Tech Pros Worldwide Forums | Help | Site Map

switches

Jonathan H. Justvig
Guest
 
Posts: n/a
#1: Aug 10 '06
Is it possible to call a function within a switch? My function call is
bypassed somehow.

int startmenu()
{
exitgame = 0;

int line_num;
for (line_num = 0; line_num < 12; line_num++)
{
puts (menu[line_num]);
}

printf ("Command: ");

int c = tolower (getchar());
switch (c)
{
case ('s'):
/* Start Game */
puts ("Starting game...");
printf ("Enter your name: ");
scanf ("%s", cname);
puts ("(F)ighter");
puts ("(S)orceress");
puts ("(T)hief");
printf ("Enter your class: ");
class(); /* <<-- This function call */
break;
case ('l'):
/* Load Game */
puts ("Loading has not been established yet.");
break;
case ('q'):
/* Quit Game */
break;
case EOF:
/* Oh, no! Problems! */
break;
// default:
// /* Incase of Wrong Choice */
// puts ("Wrong choice, try again.");
// break;
}
}

Ian Collins
Guest
 
Posts: n/a
#2: Aug 10 '06

re: switches


Jonathan H. Justvig wrote:
Quote:
Is it possible to call a function within a switch? My function call is
bypassed somehow.
>
Yes and you've made several in your code (puts,printf,scanf).

Unless you post a self contained and compilable example that shows your
problem, we won't be able to help.
Quote:
int startmenu()
{
exitgame = 0;
>
int line_num;
for (line_num = 0; line_num < 12; line_num++)
{
puts (menu[line_num]);
}
>
printf ("Command: ");
>
int c = tolower (getchar());
switch (c)
{
case ('s'):
/* Start Game */
puts ("Starting game...");
printf ("Enter your name: ");
scanf ("%s", cname);
puts ("(F)ighter");
puts ("(S)orceress");
puts ("(T)hief");
printf ("Enter your class: ");
class(); /* <<-- This function call */
break;
case ('l'):
/* Load Game */
puts ("Loading has not been established yet.");
break;
case ('q'):
/* Quit Game */
break;
case EOF:
/* Oh, no! Problems! */
break;
// default:
// /* Incase of Wrong Choice */
// puts ("Wrong choice, try again.");
// break;
}
}

--
Ian Collins.
Snis Pilbor
Guest
 
Posts: n/a
#3: Aug 10 '06

re: switches



Jonathan H. Justvig wrote:
Quote:
Is it possible to call a function within a switch? My function call is
bypassed somehow.
>
int startmenu()
{
exitgame = 0;
>
int line_num;
for (line_num = 0; line_num < 12; line_num++)
{
puts (menu[line_num]);
}
>
printf ("Command: ");
>
int c = tolower (getchar());
switch (c)
{
case ('s'):
/* Start Game */
puts ("Starting game...");
printf ("Enter your name: ");
scanf ("%s", cname);
puts ("(F)ighter");
puts ("(S)orceress");
puts ("(T)hief");
printf ("Enter your class: ");
class(); /* <<-- This function call */
break;
case ('l'):
/* Load Game */
puts ("Loading has not been established yet.");
break;
case ('q'):
/* Quit Game */
break;
case EOF:
/* Oh, no! Problems! */
break;
// default:
// /* Incase of Wrong Choice */
// puts ("Wrong choice, try again.");
// break;
}
}
It's impossible for us to help when we don't know what the "class()"
function does.
What I would recommend is, at the top of the class() function, put in a
line like

printf( "Debug 1\n" );

Then run the program and you can check if it prints "Debug 1" where you
think class() should be called. If not, then indeed class() isn't
getting called (which, given the above code, would be pretty weird).
If so, move the printf line further down, using it to "feel out" where
the problem is. Do this a few times and before you know it you'll find
yourself staring at a for loop followed immediately by a misplaced
semicolon, or something else like that.

Keith Thompson
Guest
 
Posts: n/a
#4: Aug 10 '06

re: switches


"Jonathan H. Justvig" <crimson3@cox.netwrites:
Quote:
Is it possible to call a function within a switch?
Of course.
Quote:
My function call is bypassed somehow.
>
int startmenu()
{
exitgame = 0;
>
int line_num;
for (line_num = 0; line_num < 12; line_num++)
{
puts (menu[line_num]);
}
>
printf ("Command: ");
>
int c = tolower (getchar());
getchar() returns the next character from stdin (or EOF if there's no
more input available). If you type 's', the system won't process your
input until you hit the return key, which will then cause getchar() to
return '\n'.

I don't know whether that's your problem, but it might be something
related to that.

To help track it down, add a default case that shows the value of the
character (use "'%c'" if it's printable, "%d" if it isn't).
Quote:
switch (c)
{
case ('s'):
[code snipped]
Quote:
}
--
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.
Jonathan H. Justvig
Guest
 
Posts: n/a
#5: Aug 10 '06

re: switches


Ian Collins wrote:
Quote:
Jonathan H. Justvig wrote:
Quote:
>Is it possible to call a function within a switch? My function call is
>bypassed somehow.
Quote:
Yes and you've made several in your code (puts,printf,scanf).
Quote:
Unless you post a self contained and compilable example that shows your
problem, we won't be able to help.
Here is a very condensed version causing the same problem.

#include <stdio.h>
char c;
char *cclass;
int cstr, cdex, cint, cvit;
int heal, chealth, cmaxhealth;
char cname [15];

int fighter()
{
/* Building Fighter */
cclass = "Fighter";
}

int startmenu()
{
puts ("S)tart Game");
printf ("Command: ");

int c = tolower (getchar());
switch (c)
{
case ('s'):
puts ("Select Class");
puts ("(F)ighter"); /* It stops about here */
printf ("Enter your class: ");
int c = tolower (getchar());
switch (c)
{
case ('f'):
fighter();
break;
}
}
}

int main()
{
startmenu();
}

-- Jon
Keith Thompson
Guest
 
Posts: n/a
#6: Aug 10 '06

re: switches


"Jonathan H. Justvig" <crimson3@cox.netwrites:
Quote:
Ian Collins wrote:
Quote:
>Jonathan H. Justvig wrote:
Quote:
>>Is it possible to call a function within a switch? My function call is
>>bypassed somehow.
>
Quote:
>Yes and you've made several in your code (puts,printf,scanf).
>
Quote:
>Unless you post a self contained and compilable example that shows your
>problem, we won't be able to help.
>
Here is a very condensed version causing the same problem.
>
#include <stdio.h>
char c;
char *cclass;
int cstr, cdex, cint, cvit;
int heal, chealth, cmaxhealth;
char cname [15];
>
int fighter()
{
/* Building Fighter */
cclass = "Fighter";
}
>
int startmenu()
{
puts ("S)tart Game");
printf ("Command: ");
>
int c = tolower (getchar());
switch (c)
{
case ('s'):
puts ("Select Class");
puts ("(F)ighter"); /* It stops about here */
printf ("Enter your class: ");
int c = tolower (getchar());
switch (c)
{
case ('f'):
fighter();
break;
}
}
}
>
int main()
{
startmenu();
}
First, I'll point out a few problems in this code that probably aren't
relevant to your problem.

You declare three functions as returning int, but you don't return a
value from any of them.

If a function takes no arguments, it's better to say so explicitly:
int fighter(void)

You mix declarations and statements. This is allowed in C99, but not
in C90 (though some pre-C99 compilers support it as an extension).

You use tolower(), but you don't have a "#include <ctype.h>".

The real problem, I think, is what I guessed previously. getchar()
returns the next character you type. You see the prompt, then you
type 's', then you hit <enter>. The 's' causes getchar() to return
's', and the <entercauses it to return '\n'.

If you type 'sf' *without* pressing <enterafter the 's' (i.e., you
type 'f' before seeing the "Select Class" prompt), you should see the
correct behavior.

After calling getchar() to read a character, you need to read and
discard all following output up to and including the first '\n'. If
the initial getchar() call returns '\n', then the user entered an
empty line, which presumably is an error.

--
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.
Jonathan H. Justvig
Guest
 
Posts: n/a
#7: Aug 10 '06

re: switches


Here it is again with your advice and correction. 'sf' does returns the
correct results. Is the problem because there is a switch within a
switch? I can't seem to get another prompt after I type 's' and fflush
(stdin);

[snip]

#include <stdio.h>
#include <ctype.h>
char c;
char *cclass;

int fighter(void)
{
/* Building Fighter */
cclass = "Fighter";
}

int startmenu(void)
{
puts ("S)tart Game");
printf ("Command: ");

int c = tolower (getchar());
switch (c)
{
case ('s'):
puts ("Select Class");
puts ("(F)ighter");
printf ("Enter your class: ");
fflush(stdin);
puts ("debug 1");
int c = tolower (getchar());
puts ("debug 2");
switch (c)
{
puts ("debug 3");
case ('f'):
puts ("debug 4");
fighter();
printf ("%s",cclass);
break;
}
default:
printf ("%d", c);
}
}

int main(void)
{
startmenu();
}

[snip]

Keith Thompson wrote:
Quote:
You declare three functions as returning int, but you don't return a
value from any of them.
Hopefully, corrected.
Quote:
You mix declarations and statements. This is allowed in C99, but not
in C90 (though some pre-C99 compilers support it as an extension).
Is ' int c = tolower (getchar()); ' what you mean? What would you
suggest instead?
Quote:
You use tolower(), but you don't have a "#include <ctype.h>".
Now it's been 'included'.
Quote:
After calling getchar() to read a character, you need to read and
discard all following output up to and including the first '\n'. If
the initial getchar() call returns '\n', then the user entered an
empty line, which presumably is an error.
I tried fflush(stdin); but that didn't seem to work. I did trying to
print out what was in the variable char 'c' and get strange results
mostly when I use %c or %d.

Thanks for your help thus far.

-- Jon
levis501@yahoo.com
Guest
 
Posts: n/a
#8: Aug 10 '06

re: switches



Jonathan H. Justvig wrote:
[snip]
Quote:
fflush(stdin);
[snip]
Quote:
I tried fflush(stdin); but that didn't seem to work. I did trying to
print out what was in the variable char 'c' and get strange results
mostly when I use %c or %d.
Hi Jonathan,
fflush() flushes output streams, and should have no effect on input
streams like stdin.
You may just want to add a while loop that reads characters until it
gets the one you want (or until end of file).

-Steve

Keith Thompson
Guest
 
Posts: n/a
#9: Aug 10 '06

re: switches


"Jonathan H. Justvig" <crimson3@cox.netwrites:
Quote:
Here it is again with your advice and correction. 'sf' does returns
the correct results. Is the problem because there is a switch within
a switch? I can't seem to get another prompt after I type 's' and
fflush (stdin);
No, it's not because you have a switch within a switch. It's because
getchar() does exactly what it's supposed to do. If you type 's'
immediately followed by 'f', the first call to getchar() returns 's'
and the second returns 'f'. If you type 's' immediately followed by
the <enterkey, the first call to getchar() returns 's' and the
second returns '\n'.

It gives you exactly what you typed. You're just not allowing for the
fact that one of the things you typed was '\n' (or the <enterkey,
which is mapped to '\n').

Don't use fflush(stdin); it's not defined.

The system is reading a line at a time; getchar() gets the characters
only after you press <enter>. There are system-specific ways to read
one character at a time, but there's nothing portable; see question
19.1 in the comp.lang.c FAQ, <http://www.c-faq.com/>.

One solution is:

Call getchar() and save the result.
Repeatedly call getchar() and discard the result until you
see a '\n' or EOF.

Another is to read a line at a time using fget() (*not* gets()), and
just use the first character. This is probably simpler than the loop.

[...]
Quote:
Quote:
>You mix declarations and statements. This is allowed in C99, but not
>in C90 (though some pre-C99 compilers support it as an extension).
>
Is ' int c = tolower (getchar()); ' what you mean? What would you
suggest instead?
In C90, a block (a chunk of code starting with "{" and ending with "}"
needs to contain zero or more declarations followed by zero or more
statements. You can just rearrange your code to meet this
restriction. You might need to separate a variable's initialization
from its declaration to do this; for example:

int c;
/* ... */
c = tolower(getchar());

But this isn't necessary if you're not concerned about portability.
Many compilers, apparently including the one you're using, do allow
mixed declarations and statements. You might consider setting this
issue aside while you work on the other problems.

--
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.
Morris Dovey
Guest
 
Posts: n/a
#10: Aug 10 '06

re: switches


Jonathan H. Justvig (in j3wCg.5501$yO4.437@dukeread02) said:

| I tried fflush(stdin); but that didn't seem to work. I did trying
| to print out what was in the variable char 'c' and get strange
| results mostly when I use %c or %d.

Jonathan...

Sometimes indentation helps to see program structure better. I did a
bit of re-formatting and combined the c definitions in startmenu():

#include <stdio.h>
#include <ctype.h>

char c;
char *cclass;

void fighter(void)
{ /* Building Fighter */
cclass = "Fighter";
}

void startmenu(void)
{ int c;

puts ("S)tart Game");
printf ("Command: ");
c = tolower (getchar());
switch (c)
{ case ('s'):
puts ("Select Class");
puts ("(F)ighter");
printf ("Enter your class: ");
puts ("debug 1");
c = tolower (getchar());
puts ("debug 2");
switch (c)
{ puts ("debug 3");
case ('f'):
puts ("debug 4");
fighter();
printf ("%s",cclass);
break;
}
default:
printf ("%d", c);
}
}

int main(void)
{ startmenu();
return 0;
}

Here's what I got when I ran your program. Note that I put both
expected characters into the stdin stream at first opportunity. The
switches appear to be working just as expected:

C:\WINDOWS\Desktop: jhj
S)tart Game
Command: sf
Select Class
(F)ighter
Enter your class: debug 1
debug 2
debug 4
Fighter102
C:\WINDOWS\Desktop:

--
Morris Dovey
DeSoto Solar
DeSoto, Iowa USA
http://www.iedu.com/DeSoto


Keith Thompson
Guest
 
Posts: n/a
#11: Aug 10 '06

re: switches


levis501@yahoo.com writes:
Quote:
Jonathan H. Justvig wrote:
[snip]
Quote:
> fflush(stdin);
[snip]
Quote:
>I tried fflush(stdin); but that didn't seem to work. I did trying to
>print out what was in the variable char 'c' and get strange results
>mostly when I use %c or %d.
>
fflush() flushes output streams, and should have no effect on input
streams like stdin.
You may just want to add a while loop that reads characters until it
gets the one you want (or until end of file).
Correction: fflush() on an input stream invokes undefined behavior.
Some systems define the behavior, but you can't count on it in
portable code.

--
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.
Jonathan H. Justvig
Guest
 
Posts: n/a
#12: Aug 10 '06

re: switches


Keith Thompson wrote:
Quote:
After calling getchar() to read a character, you need to read and
discard all following output up to and including the first '\n'. If
the initial getchar() call returns '\n', then the user entered an
empty line, which presumably is an error.
Sorry, I'm a little slow. I just now understood that if I issue an
extra getchar() to read the '\n'. It now gives me the prompt for the
next switch. It's probably not the best but it seems to work
regardless. Again, thanks for your help.

-- Jon
Barry Schwarz
Guest
 
Posts: n/a
#13: Aug 10 '06

re: switches


On 9 Aug 2006 19:02:01 -0700, levis501@yahoo.com wrote:
Quote:
>
>Jonathan H. Justvig wrote:
>[snip]
Quote:
> fflush(stdin);
>[snip]
Quote:
>I tried fflush(stdin); but that didn't seem to work. I did trying to
>print out what was in the variable char 'c' and get strange results
>mostly when I use %c or %d.
>
>Hi Jonathan,
fflush() flushes output streams, and should have no effect on input
>streams like stdin.
fflush is defined only for output streams. Attempting to use it on an
input stream invokes undefined behavior.
Quote:
>You may just want to add a while loop that reads characters until it
>gets the one you want (or until end of file).
>
>-Steve

Remove del for email
Richard Heathfield
Guest
 
Posts: n/a
#14: Aug 10 '06

re: switches


[Others have pretty much picked your code apart, and answered your original
question in the process. But there are one or two points of interest that
remain, which I *think* have not yet been mentioned - so, with your
indulgence...]

Jonathan H. Justvig said:
Quote:
#include <stdio.h>
char c;
char *cclass;
Make this const char *cclass because you use it for pointing at string
literals.
Quote:
int cstr, cdex, cint, cvit;
int heal, chealth, cmaxhealth;
char cname [15];
That's a lot of file scope data for such a simple program. Is it really
necessary? (No.)
Quote:
int fighter()
{
/* Building Fighter */
cclass = "Fighter";
}
>
int startmenu()
{
puts ("S)tart Game");
printf ("Command: ");
To ensure that the program produces the prompt before blocking for input,
either make this printf("Command:\n"); or puts("Command:"); or, if you
really want the currently active position to remain on the same line,
fflush(stdout);
Quote:
int c = tolower (getchar());
Setting aside the interleaved declaration, consider the possibility that
tolower is implemented as follows (and at least one compiler does implement
it something like this):

#define tolower(c) (((c)==EOF)?EOF:_lowercase[(c)])

If so, then your tolower call expands to:

int c = (((getchar())==EOF)?EOF:_lowercase[(getchar())]);

which calls getchar a second time if the first didn't hit the end of the
file. "Yes, very funny", you say, "but I'm sure my system doesn't implement
tolower that way. It knows it's using ASCII, so it takes advantage of
that!"

Okay, so perhaps it uses something like:

#define tolower(c) (((c) >= 'A' && (c) <= 'Z') ? (c) + ('a' - 'A') : (c))

So your call expands to:

int c = (((getchar()) >= 'A' && (getchar()) <= 'Z') ? (getchar()) + ('a' -
'A') : (getchar()))

which, if sufficient upper case letters are available, calls getchar *three*
times!

Suggested fix: capture it first. Then worry about the case. For example, you
could do:

c = getchar();
switch(tolower(c))
Quote:
switch (c)
{
Don't forget case EOF:
Quote:
case ('s'):
puts ("Select Class");
puts ("(F)ighter"); /* It stops about here */
printf ("Enter your class: ");
int c = tolower (getchar());
switch (c)
{
case ('f'):
fighter();
break;
}
}
}
You promised to return an int from startmenu(). Where is it?
Quote:
>
int main()
{
startmenu();
You promised to return an int from main(). Where is it?


Incidentally, in your original article you mentioned that you are using:

scanf ("%s", cname);

You didn't specify how much memory cname refers to, but I can assure you it
isn't enough. This is a buffer overrun waiting to happen.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Keith Thompson
Guest
 
Posts: n/a
#15: Aug 10 '06

re: switches


Richard Heathfield <invalid@invalid.invalidwrites:
Quote:
[Others have pretty much picked your code apart, and answered your original
question in the process. But there are one or two points of interest that
remain, which I *think* have not yet been mentioned - so, with your
indulgence...]
>
Jonathan H. Justvig said:
[...]
Quote:
Quote:
>int c = tolower (getchar());
>
Setting aside the interleaved declaration, consider the possibility that
tolower is implemented as follows (and at least one compiler does implement
it something like this):
>
#define tolower(c) (((c)==EOF)?EOF:_lowercase[(c)])
>
If so, then your tolower call expands to:
>
int c = (((getchar())==EOF)?EOF:_lowercase[(getchar())]);
>
which calls getchar a second time if the first didn't hit the end of the
file. "Yes, very funny", you say, "but I'm sure my system doesn't implement
tolower that way. It knows it's using ASCII, so it takes advantage of
that!"
[snip]

A conforming implementation can't define tolower() that way.

C99 7.1.4p1:

Any function declared in a header may be additionally implemented
as a function-like macro defined in the header, so if a library
function is declared explicitly when its header is included, one
of the techniques shown below can be used to ensure the
declaration is not affected by such a macro.
[...]
Any invocation of a library function that is implemented as a
macro shall expand to code that evaluates each of its arguments
exactly once, fully protected by parentheses where necessary, so
it is generally safe to use arbitrary expressions as arguments.

(C90 has similar or identical wording.)

--
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.
Richard Heathfield
Guest
 
Posts: n/a
#16: Aug 10 '06

re: switches


Keith Thompson said:

<snip>
Quote:
A conforming implementation can't define tolower() that way.
>
C99 7.1.4p1:
>
Any function declared in a header may be additionally implemented
as a function-like macro defined in the header, so if a library
function is declared explicitly when its header is included, one
of the techniques shown below can be used to ensure the
declaration is not affected by such a macro.
[...]
Any invocation of a library function that is implemented as a
macro shall expand to code that evaluates each of its arguments
exactly once, fully protected by parentheses where necessary, so
it is generally safe to use arbitrary expressions as arguments.
Thank you. For some reason I had overlooked that.

--
Richard Heathfield
"Usenet is a strange place" - dmr 29/7/1999
http://www.cpax.org.uk
email: rjh at above domain (but drop the www, obviously)
Flash Gordon
Guest
 
Posts: n/a
#17: Aug 10 '06

re: switches


Richard Heathfield wrote:

<snip>
Quote:
Quote:
>int c = tolower (getchar());
>
Setting aside the interleaved declaration, consider the possibility that
tolower is implemented as follows (and at least one compiler does implement
it something like this):
>
#define tolower(c) (((c)==EOF)?EOF:_lowercase[(c)])
>
If so, then your tolower call expands to:
>
int c = (((getchar())==EOF)?EOF:_lowercase[(getchar())]);
>
which calls getchar a second time if the first didn't hit the end of the
file. "Yes, very funny", you say, "but I'm sure my system doesn't implement
tolower is defined as a function, not a macro, by the standard. I know
the implementation is allowed to provide a macro implementation as well
but that macro is NOT allowed to evaluate the argument more than once.
N1124 includes the text:
| Any invocation of a library function that is implemented as
| a macro shall expand to code that evaluates each of its arguments
| exactly once, fully protected by parentheses where necessary, so it is
| generally safe to use arbitrary expressions as arguments.
Quote:
Suggested fix: capture it first. Then worry about the case. For example, you
could do:
>
c = getchar();
switch(tolower(c))
Not required, see above.

<snip>
--
Flash Gordon
Still sigless on this computer.
Default User
Guest
 
Posts: n/a
#18: Aug 10 '06

re: switches


Jonathan H. Justvig wrote:
Quote:
Ian Collins wrote:
Quote:
Jonathan H. Justvig wrote:
Quote:
Is it possible to call a function within a switch? My function
call is bypassed somehow.
>
Quote:
Yes and you've made several in your code (puts,printf,scanf).
>
Quote:
Unless you post a self contained and compilable example that shows
your problem, we won't be able to help.
>
Here is a very condensed version causing the same problem.
>
#include <stdio.h>
char c;
Quote:
int startmenu()
{
puts ("S)tart Game");
printf ("Command: ");
>
int c = tolower (getchar());

Besides the other problems people have pointed out, I note that you
have a variable named c and file scope, and another inside a function.
While not technically an error, that's almost always a sign of
something designed improperly, usually the "global" is a fossil left
over from an earlier stage of the program. Many compilers will issue a
diagnostic for this when run at an appropriate warning level.

At the beginning, you should always run at the maximum warning level
your compiler supports (how to do this is implementation-specific).
Treat those warnings as errors that must be corrected.




Brian

Dave Thompson
Guest
 
Posts: n/a
#19: Aug 21 '06

re: switches


On Thu, 10 Aug 2006 06:16:41 GMT, Keith Thompson <kst-u@mib.org>
wrote:
Quote:
Richard Heathfield <invalid@invalid.invalidwrites:
<snip: tolower() might be macro that multiply evaluates its arg>
Quote:
A conforming implementation can't define tolower() that way.
>
C99 7.1.4p1:
>
Any function declared in a header may be additionally implemented
as a function-like macro defined in the header, so if a library
function is declared explicitly when its header is included, one
of the techniques shown below can be used to ensure the
declaration is not affected by such a macro.
[...]
Any invocation of a library function that is implemented as a
macro shall expand to code that evaluates each of its arguments
exactly once, fully protected by parentheses where necessary, so
it is generally safe to use arbitrary expressions as arguments.
>
Except {get,put}[w]c() which have special permission (in 7.19.7.5,8
and 7.23.4.6,8 ) to evaluate the FILE* argument more than once.

Also note that a few library items are specified as function-like
macros, not functions, and thus presumably don't have this guarantee,
particularly setjmp and va_*. In C99 the added IEEE-like operations
(isnan etc.) and tgmath.h generics are specified as macros apparently
because of their not obeying the usual type conversion rules for
function calls, but one hopes shouldn't need to multiply evaluate.
Quote:
(C90 has similar or identical wording.)
- David.Thompson1 at worldnet.att.net
Closed Thread