[comp.lang.c] macros with parameters in MSC 5.0

jbaker@ee.UCLA.EDU (Joe Baker) (02/18/88)

I am a C neophyte and am looking for a solution to the following problem:

I am attempting to port the latest version of the public domain spreadsheet
calculator, sc 5.1, to an IBM PC.  I am using Microsoft C 5.0.  The
code uses the following macro to produce control characters for
comparison to input characters in case statements and the like:

#define ctl(c) ('c'&037)

This requires parameter substitution within a character constant, which
is not allowed in MSC5.0 (My reading of Kernighan & Ritchie pg. 207
seems to indicate that they don't allow it either.  However, the 
program compiles and runs on lots of systems.)

The Microsoft manual suggests use of the 'stringizing' operator, #,
but this produces a string literal instead of a character constant.

I have come up with some ugly fixes, but would like to know: what is
the Right Way to do this?

Thanks,


- Joe Baker, Dept. of Electrical Engineering
6731 Boelter Hall, UCLA, L.A., CA 90024 (213) 825-7079, 825-2327
ARPA: jbaker@ee.ucla.edu UUCP: {ihnp4|randvax|ucbvax}!ucla-cs!uclaee!jbaker

"Presumptions that the church should be trying to improve housing for the 
poor...that the church should be small and impoverished...are hidden 
presumptions that I see all the time.  Are _you_ housing the homeless in your 
home?  What's the Empire State Building doing to help the homeless...?  
Why should people just pick on the churches?  There's a fairness element here."
              - Pastor of the Fifth Avenue Presbyterian Church in NYC

      

karl@haddock.ISC.COM (Karl Heuer) (02/19/88)

In article <11879@brl-adm.ARPA> jbaker@ee.UCLA.EDU (Joe Baker) writes:
>  #define ctl(c) ('c'&037)
>... is not allowed in MSC5.0

Nor in ANSI C.

>What is the Right Way to do this?

Change the definition to "#define ctl(c) ((c)&037)" and write "ctl('P')"
rather than "ctl(P)".  You may also want to change the name, in case you
overlook some references.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/19/88)

In article <11879@brl-adm.ARPA> jbaker@ee.UCLA.EDU (Joe Baker) writes:
>#define ctl(c) ('c'&037)

Yes, whoever did this was deliberately violating the K&R rules, because
they knew that their C preprocessor (probably based on Reiser's) would
allow it.  This particular macro and Berkeley's _IOR etc. ioctl macros
are the most common cases of this nonportable construct.  Neither was
necessary, since the desired effect could have been achieved portably.

The correct way to have done this would have been:
	#define ctl(c) ((c)&037)
and include the '' in its invocation:
	case ctl('G'):

With ANSI C, or any C preprocessor that includes the stringizing
feature, you can make the original usage work by
	#define ctl(c) (#c[0]&037)
which would cause
	case ctl(G):
to expand to
	case ("G"[0]&037):
which is equivalent to
	case ('G'&037):
Personally, I prefer the other way I described, because it also works
with pre-ANSI C preprocessors.

edw@IUS1.CS.CMU.EDU (Eddie Wyatt) (02/19/88)

> >  #define ctl(c) ('c'&037)
> >... is not allowed in MSC5.0
> 
> Nor in ANSI C.

  Does this imply that a macro parameter will nolonger be expanded in
strings too?

#define DEBUG_CALL(xxx)	if ((xxx) != OK) {				 \
  			    (void) printf("xxx\n");			 \
  			    (void) printf("%s %d\n\n",__FILE__,__LINE__);\
                            clearline(); }
-- 

Eddie Wyatt 				e-mail: edw@ius1.cs.cmu.edu

scjones@sdrc.UUCP (Larry Jones) (02/19/88)

In article <11879@brl-adm.ARPA>, jbaker@ee.UCLA.EDU (Joe Baker) writes:
< #define ctl(c) ('c'&037)
< 
< This requires parameter substitution within a character constant, which
< is not allowed in MSC5.0 (My reading of Kernighan & Ritchie pg. 207
< seems to indicate that they don't allow it either.  However, the 
< program compiles and runs on lots of systems.)
< 
< The Microsoft manual suggests use of the 'stringizing' operator, #,
< but this produces a string literal instead of a character constant.

Just stringize and then pick the character you want out of the string:

#define ctl(c) (#c[0]&037)

A sufficiently clever compiler will just compile this into a character
constant.
-- 

----
Larry Jones                         UUCP: uunet!sdrc!scjones
SDRC                                MAIL: 2000 Eastman Dr., Milford, OH  45150
                                    AT&T: (513) 576-2070
"When all else fails, read the directions."

gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/19/88)

In article <898@PT.CS.CMU.EDU> edw@IUS1.CS.CMU.EDU (Eddie Wyatt) writes:
>  Does this imply that a macro parameter will nolonger be expanded in
>strings too?

Yes -- it never was supposed to be expanded, according to K&R specs.
The Reiser C preprocessor did anyway, though -- that's a bug.

kulik@xyzzy.UUCP (Al Kulik) (02/20/88)

>In article <898@PT.CS.CMU.EDU> edw@IUS1.CS.CMU.EDU (Eddie Wyatt) writes:
>  Does this imply that a macro parameter will nolonger be expanded in
>strings too?

That's right. You have to use the '#' operator, e.g.

#define str(s) # s
        .
        .
        .
char *p = str(somestring);

which results in

char *p = "somestring";

-- 
Al Kulik, Data General.		        Uucp: ...!mcnc!rti!xyzzy!kulik
					Arpa/Csnet:  kulik@dg-rtp.DG.COM

karl@haddock.ISC.COM (Karl Heuer) (02/20/88)

In article <7277@brl-smoke.ARPA> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
>In article <11879@brl-adm.ARPA> jbaker@ee.UCLA.EDU (Joe Baker) writes:
>>#define ctl(c) ('c'&037)
>
>Yes, whoever did this was deliberately violating the K&R rules

I looked it up when I first saw this hack, and I concluded that K&R didn't
establish an unambiguous rule.  The book says that macros are not expanded
inside strings, but I don't think it specifies whether macro *arguments* are
expanded inside strings within the macro.

>With ANSI C, or any C preprocessor that includes the stringizing
>feature, you can make the original usage work by
>	#define ctl(c) (#c[0]&037)
>which would cause
>	case ctl(G):
>to expand to
>	case ("G"[0]&037):

Umm, I believe that according to the C rules, that's a non-constant expression
(and hence illegal as a case label).

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

flaps@csri.toronto.edu (Alan J Rosenthal) (02/21/88)

In article <11879@brl-adm.ARPA> jbaker@ee.UCLA.EDU (Joe Baker) writes:
>#define ctl(c) ('c'&037)
...
>I have come up with some ugly fixes, but would like to know: what is
>the Right Way to do this?

how about
    #define ctl(c)((c) & 31)
and call it as
    ctl('a')

-- 
"noalias considered sailaon"

gnu@hoptoad.uucp (John Gilmore) (02/21/88)

jbaker@ee.UCLA.EDU (Joe Baker) wrote:
> #define ctl(c) ('c'&037)
> I have come up with some ugly fixes, but would like to know: what is
> the Right Way to do this?

The Right Way is to send in a comment to the ANSI C committee, complaining
that there is no Right Way to do this.

This change caused us to have to fix more than 50 files in Berkeley
Unix.  We wouldn't have minded changing all the macro definitions -- we
know that substitution inside strings is a hack -- it's that we had to
change all the CALLERS too that bugged us!

[Responses of the form: "Well, you already fixed your code, so why should
we make the standard reasonable?" are bogus.  A useful capability was removed,
and replaced with a less capable set of features.]

>                                                     However, the 
> program compiles and runs on lots of systems.

Something like 99% of the Unix systems, I'd guess, since they all seem to
use John Reiser's cpp -- it works, why rewrite it?
-- 
{pyramid,ptsfa,amdahl,sun,ihnp4}!hoptoad!gnu			  gnu@toad.com
		"Watch me change my world..." -- Liquid Theatre

gnu@l nptoad.uucp (John Gilmore) (02/21/88)

jbaker@ee.UCLA.EDU (Joe Baker) wrote:
> #define ctl(c) ('c'&037)
> I have come up with some ugly fixes, but would like to know: what is
> the Right Way to do this?

The Right Way is to send in a comment to the ANSI C committee, complaining
that there is no Right Way to do this.

This change caused us to have to fix more than 50 files in Berkeley
Unix.  We wouldn't have minded changing all the macro definitions -- we
know that substitution inside strings is a hack -- it's that we had to
change all the CALLERS too that bugged us!

[Responses of the form: "Well, you already fixed your code, so why should
we make the standard reasonable?" are bogus.  A useful capability was removed,
and replaced with a less capable set of features.]

>                                                     However, the 
> program compiles and runs on lots of systems.

Something like 99% of the Unix systems, I'd guess, since they all seem to
use John Reiser's cpp -- it works, why rewrite it?
-- 
{pyramid,ptsfa,amdahl,sun,ihnp4}!loptoad!gnu			  gnu@toad.com
		"Watch me change my world..." -- Liquid Theatre

gwyn@brl-smoke.ARPA (Doug Gwyn ) (02/22/88)

In article <4099@hoptoad.uucp> gnu@hoptoad.uucp (John Gilmore) writes:
>jbaker@ee.UCLA.EDU (Joe Baker) wrote:
>> #define ctl(c) ('c'&037)
>This change caused us to have to fix more than 50 files in Berkeley
>Unix.  We wouldn't have minded changing all the macro definitions -- we
>know that substitution inside strings is a hack -- it's that we had to
>change all the CALLERS too that bugged us!
>[Responses of the form: "Well, you already fixed your code, so why should
>we make the standard reasonable?" are bogus.  A useful capability was removed,
>and replaced with a less capable set of features.]

First, this was NOT a change to the C language.  K&R already guaranteed
that macro substitution would not occur inside string and character
literals (section 12.1 of Appendix A).  I daresay there are more
instances of C compilers currently that do not do such substitution than
those that do; generally only compilers adapted from AT&T's source (the
Reiser C preprocessor in particular) have this bug.

X3J11, realizing that the facility was nevertheless useful, designed an
alternative approach that was compatible with the K&R definition.

To see what is wrong with the Reiser method, try the following program:

#include <stdio.h>
#define TEST(a,b) ((void)fprintf(stderr,"This is a test: 0x%x\n",(a)^(b)))
main()	{
	TEST(0xFF<<4,0xFFFF>>4);
	return 0;
	}

bts@sas.UUCP (Brian T. Schellenberger) (02/28/88)

In article <11879@brl-adm.ARPA> jbaker@ee.UCLA.EDU (Joe Baker) writes:
|#define ctl(c) ('c'&037)
|what is the Right Way to do this?  (under dpANS)

#define ctl(c)  ((* #c) & 037))

-- 
                                                         --Brian.
(Brian T. Schellenberger)				 ...!mcnc!rti!sas!bts

DISCLAIMER:  Whereas Brian Schellenberger (hereinafter "the party of the first 

ado@elsie.UUCP (Arthur David Olson) (02/29/88)

> > #define ctl(c) ('c'&037)
> > what is the Right Way to do this?  (under dpANS)
> 
> #define ctl(c)  ((* #c) & 037))

Not if you plan to use code such as
		switch (value) {
			case ctl(a):
				...
-- 
ado@vax2.nlm.nih.gov		ADO, VAX, and NIH are Ampex and DEC trademarks

fox@alice.marlow.reuters.co.uk (Paul Fox) (03/03/88)

In article <898@PT.CS.CMU.EDU> edw@IUS1.CS.CMU.EDU (Eddie Wyatt) writes:
>> >  #define ctl(c) ('c'&037)
>> >... is not allowed in MSC5.0
>> 
>> Nor in ANSI C.
>
>  Does this imply that a macro parameter will nolonger be expanded in
>strings too?
>
>#define DEBUG_CALL(xxx)	if ((xxx) != OK) {				 \
>  			    (void) printf("xxx\n");			 \
>  			    (void) printf("%s %d\n\n",__FILE__,__LINE__);\
>                            clearline(); }
>-- 
ANSI gets around this via the '#' and '##' operators -- available within
the preprocessor phase only. As I read it 

# define	CTRL(x)		#x & 037
		CTRL(A);

gives:		"A" & 037

# define	CTRL(x)		'##x##' & 037
		CTRL(A);

gives:		'A' & 037

kulik@xyzzy.UUCP (Al Kulik) (03/05/88)

In article <290@alice.marlow.reuters.co.uk> fox@alice.marlow.reuters.co.uk (Paul Fox) writes:
>ANSI gets around this [macro argument substitution in string literals] via the
>'#' and '##' operators -- available within the preprocessor phase only. As I 
>read it 
>
># define	CTRL(x)		#x & 037
>		CTRL(A);
>
>gives:		"A" & 037
>
># define	CTRL(x)		'##x##' & 037
>		CTRL(A);        ^^^^^^^
>
>gives:		'A' & 037
>

I don't know about this. It seems to me that this would result in
'##x##' & 037. '##x##' is a character constant which is a preprocessor
token; the preprocessor will not recognize the ##s within the token, they're
just part of the constant.

In the first case above, "A" & 037 results in the address of the literal
"A" being ANDed bitwise with the constant 037, which may not be what you want.

To obtain something like the second case:

#define CTRL(x)	#x[0] & 037.








-- 
Al Kulik, Data General.		        Uucp: ...!mcnc!rti!xyzzy!kulik
					Arpa/Csnet:  kulik@dg-rtp.DG.COM

mouse@mcgill-vision.UUCP (der Mouse) (03/10/88)

In article <7309@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
> In article <4099@hoptoad.uucp> gnu@hoptoad.uucp (John Gilmore) writes:
>> jbaker@ee.UCLA.EDU (Joe Baker) wrote:
>>> #define ctl(c) ('c'&037)
>> This change caused us to have to fix more than 50 files in Berkeley
>> Unix.  [...A useful capability was removed, and replaced with a less
>> capable set of features.]
> First, this was NOT a change to the C language.  K&R already
> guaranteed that macro substitution would not occur inside string and
> character literals (section 12.1 of Appendix A).

So?  Macro arguments aren't macros.  I looked for a statement in K&R
that said that Reiser behavior was forbidden and failed to find
anything clear-cut.

The statement in 12.1 of Appendix A says that "Text inside a string or
a character constant is not subject to replacement.", but they don't
make it clear whether they mean replacement of macros with their
expansions or all replacement arising from the preprocessor.

> I daresay there are more instances of C compilers currently that do
> not do such substitution than those that do; [most that do are
> derived from AT&T's Reiser cpp].

Are you sure?  I would have guessed the other way.  I have no idea
where to look to obtain statistics to settle this; can anyone cite any
reference to such numbers?

> To see what is wrong with the Reiser method, try [...]:
> #define TEST(a,b) ((void)fprintf(stderr,"This is a test: 0x%x\n",(a)^(b)))

Yeah, and to see what's wrong with the ++ operator, try:

main() {  int i,j;
          i = 7;
          j = i++ + i++ + i++;
          printf("i = %d, j = %d\n",i,j);  }

The behavior exhibited by Reiser preprocessors is "wrong" only in that
it isn't how you believe it ought to work.  I see nothing wrong with
it.  The cited piece of K&R arguably supports you, but it arguably does
not support you.  And I claim that history supports me, because the
Reiser cpp is closer to the original cpp, the one used back when K&R
was written, than anything else around.  (Or at least so I believe, but
on trying I find I can't provide a source for this claim.  Can anyone
cite a source to support or demolish it?)

					der Mouse

			uucp: mouse@mcgill-vision.uucp
			arpa: mouse@larry.mcrcim.mcgill.edu

gwyn@brl-smoke.ARPA (Doug Gwyn ) (03/24/88)

In article <983@mcgill-vision.UUCP> mouse@mcgill-vision.UUCP (der Mouse) writes:
>The statement in 12.1 of Appendix A says that "Text inside a string or
>a character constant is not subject to replacement.", but they don't
>make it clear whether they mean replacement of macros with their
>expansions or all replacement arising from the preprocessor.

You're the first person I've encountered who doesn't take that
sentence IN CONTEXT to mean what I said.  Every AT&T compiler
person I've consulted (which is several) have agreed that the
Reiser CPP incorrectly implements this aspect of K&R.  Certainly
X3J11 thinks so.