Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #12850 > unrolled thread

A variation of #

Started byAndrey Vul <andrey.vul@gmail.com>
First post2011-11-07 10:53 -0800
Last post2011-11-07 16:46 -0800
Articles 14 — 7 participants

Back to article view | Back to comp.lang.c


Contents

  A variation of # Andrey Vul <andrey.vul@gmail.com> - 2011-11-07 10:53 -0800
    Re: A variation of # Ian Collins <ian-news@hotmail.com> - 2011-11-08 07:59 +1300
      Re: A variation of # Andrey Vul <andrey.vul@gmail.com> - 2011-11-07 11:11 -0800
        Re: A variation of # James Kuyper <jameskuyper@verizon.net> - 2011-11-07 15:07 -0500
          Re: A variation of # lawrence.jones@siemens.com - 2011-11-07 17:53 -0500
            Re: A variation of # James Kuyper <jameskuyper@verizon.net> - 2011-11-07 18:31 -0500
              Re: A variation of # lawrence.jones@siemens.com - 2011-11-08 09:16 -0500
            Re: A variation of # Thad Smith <ThadSmith@acm.org> - 2011-11-07 19:51 -0700
            Re: A variation of # Harald van Dijk <truedfx@gmail.com> - 2011-11-08 09:01 -0800
              Re: A variation of # James Kuyper <jameskuyper@verizon.net> - 2011-11-08 12:15 -0500
          Re: A variation of # Andrey Vul <andrey.vul@gmail.com> - 2011-11-07 17:32 -0800
            Re: A variation of # James Kuyper <jameskuyper@verizon.net> - 2011-11-07 21:17 -0500
      Re: A variation of # Andrey Vul <andrey.vul@gmail.com> - 2011-11-07 11:08 -0800
    Re: A variation of # Peter Nilsson <airia@acay.com.au> - 2011-11-07 16:46 -0800

#12850 — A variation of #

FromAndrey Vul <andrey.vul@gmail.com>
Date2011-11-07 10:53 -0800
SubjectA variation of #
Message-ID<8f2cadb2-614d-4754-8bc3-bb7c063524ae@c16g2000pre.googlegroups.com>
To stringify pp-constants, we use #foo notation.
Is there a method of charifying constants defined on the preprocessor
level, assuming the precondition of length being 1 is true?
That is, does there exist a pp-builtin CHARIFY such that CHARIFY(x) =
'x' ?

[toc] | [next] | [standalone]


#12851

FromIan Collins <ian-news@hotmail.com>
Date2011-11-08 07:59 +1300
Message-ID<9hqo41F4bgU2@mid.individual.net>
In reply to#12850
On 11/ 8/11 07:53 AM, Andrey Vul wrote:
> To stringify pp-constants, we use #foo notation.
> Is there a method of charifying constants defined on the preprocessor
> level, assuming the precondition of length being 1 is true?
> That is, does there exist a pp-builtin CHARIFY such that CHARIFY(x) =
> 'x' ?

Something like

#define CHAR(x) #x [0]

?

-- 
Ian Collins

[toc] | [prev] | [next] | [standalone]


#12852

FromAndrey Vul <andrey.vul@gmail.com>
Date2011-11-07 11:11 -0800
Message-ID<73822171-7a92-4420-9eea-e74bbeda1ff8@x28g2000prb.googlegroups.com>
In reply to#12851
On Nov 7, 1:59 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> On 11/ 8/11 07:53 AM, Andrey Vul wrote:
>
> > To stringify pp-constants, we use #foo notation.
> > Is there a method of charifying constants defined on the preprocessor
> > level, assuming the precondition of length being 1 is true?
> > That is, does there exist a pp-builtin CHARIFY such that CHARIFY(x) =
> > 'x' ?
>
> Something like
>
> #define CHAR(x) #x [0]
>

Can't be used inside switch.

[toc] | [prev] | [next] | [standalone]


#12855

FromJames Kuyper <jameskuyper@verizon.net>
Date2011-11-07 15:07 -0500
Message-ID<4EB83A82.1080100@verizon.net>
In reply to#12852
On 11/07/2011 02:11 PM, Andrey Vul wrote:
> On Nov 7, 1:59 pm, Ian Collins <ian-n...@hotmail.com> wrote:
>> On 11/ 8/11 07:53 AM, Andrey Vul wrote:
>>
>>> To stringify pp-constants, we use #foo notation.
>>> Is there a method of charifying constants defined on the preprocessor
>>> level, assuming the precondition of length being 1 is true?

I presume there's some reason why the constants cannot, themselves, be
defined as character constants?

>>> That is, does there exist a pp-builtin CHARIFY such that CHARIFY(x) =
>>> 'x' ?
>>
>> Something like
>>
>> #define CHAR(x) #x [0]
>>
> 
> Can't be used inside switch.

There's no simple way I can think of to define a macro that generates a
character constant whose value depends upon the expansion of another
macro. I did, however, manage to come up with this ugly monstrosity,
which cannot possibly qualify as "simple", which I've inserted into some
test code:

#include <stdlib.h>
#define TRICAT(a, b, c) a ## b ## c
#define CHAR(a, b, c) TRICAT(a, b, c)

#define CASE1 x

int main(int argc, char *argv[])
{
    if(argc <= 1)
        return EXIT_FAILURE;
    switch (*argv[1])
    {
    case CHAR('
        , CASE1, '
        ): break;
    default:
        return EXIT_SUCCESS;
    }
    return EXIT_FAILURE;
}

The key thing that makes this work is that ' immediately followed by a
newline is not recognized as any other type of pre-processing token, so
it counts as a preprocessing token of it's own, under the classification
"each non-white-space character that cannot be one of the above" (6.4p1).

The two-level expansion allows CASE1 to be expanded to x before being
concatenated with the ' tokens.

If you can convince the relevant person to define the relevant constants
as character constants, that would make things a lot easier.

[toc] | [prev] | [next] | [standalone]


#12859

Fromlawrence.jones@siemens.com
Date2011-11-07 17:53 -0500
Message-ID<v44mo8-lfm.ln1@jones.homeip.net>
In reply to#12855
James Kuyper <jameskuyper@verizon.net> wrote:
> 
> #include <stdlib.h>
> #define TRICAT(a, b, c) a ## b ## c
> #define CHAR(a, b, c) TRICAT(a, b, c)
> 
> #define CASE1 x
> 
...
>     case CHAR('
>         , CASE1, '
>         ): break;

Nice try, but no cigar.  The ## operator requires that the result be a
valid pp-token and, depending on the order in which the operators are
evaluated, you either end up with 'x or x', neither of which are valid
pp-tokens.
-- 
Larry Jones

You know how Einstein got bad grades as a kid?  Well MINE are even WORSE!
-- Calvin

[toc] | [prev] | [next] | [standalone]


#12860

FromJames Kuyper <jameskuyper@verizon.net>
Date2011-11-07 18:31 -0500
Message-ID<4EB86A45.7030305@verizon.net>
In reply to#12859
On 11/07/2011 05:53 PM, lawrence.jones@siemens.com wrote:
> James Kuyper <jameskuyper@verizon.net> wrote:
>>
>> #include <stdlib.h>
>> #define TRICAT(a, b, c) a ## b ## c
>> #define CHAR(a, b, c) TRICAT(a, b, c)
>>
>> #define CASE1 x
>>
> ...
>>     case CHAR('
>>         , CASE1, '
>>         ): break;
> 
> Nice try, but no cigar.  The ## operator requires that the result be a
> valid pp-token and, depending on the order in which the operators are
> evaluated, you either end up with 'x or x', neither of which are valid
> pp-tokens.

I hadn't considered that issue, but taking a look at 6.10.3.3p3, I found
that it says "each each instance of a ## preprocessing token
in the replacement list (not from an argument) is deleted and the
preceding preprocessing token is concatenated with the following
preprocessing token. ... If the result is not a valid preprocessing
token, the behavior is undefined." It seems to me ambiguous whether "the
result" it refers to is the result of each concatenation, or the
combined result of all of the concatenations.

I'm not going to argue strongly over this. I think this is a horribly
ugly solution to what should be a simple problem; if it actually fails
to be a solution by reason of having undefined behavior, I'm not going
to lose any sleep over it.

[toc] | [prev] | [next] | [standalone]


#12894

Fromlawrence.jones@siemens.com
Date2011-11-08 09:16 -0500
Message-ID<n6qno8-etn.ln1@jones.homeip.net>
In reply to#12860
James Kuyper <jameskuyper@verizon.net> wrote:
> 
> I hadn't considered that issue, but taking a look at 6.10.3.3p3, I found
> that it says "each each instance of a ## preprocessing token
> in the replacement list (not from an argument) is deleted and the
> preceding preprocessing token is concatenated with the following
> preprocessing token. ... If the result is not a valid preprocessing
> token, the behavior is undefined." It seems to me ambiguous whether "the
> result" it refers to is the result of each concatenation, or the
> combined result of all of the concatenations.

I think it's pretty clear from context that it's talking about each
replacement individually.  For a token-based preprocessor, you either
need each result to be a token or you need the concept of executing a
bunch of operators in parallel (which we don't have in C).
-- 
Larry Jones

Hey!  What's the matter?  Can't you take a joke?!  It was a JOKE! -- Calvin

[toc] | [prev] | [next] | [standalone]


#12871

FromThad Smith <ThadSmith@acm.org>
Date2011-11-07 19:51 -0700
Message-ID<j9a5g0$5b0$1@speranza.aioe.org>
In reply to#12859
On 11/7/2011 3:53 PM, lawrence.jones@siemens.com wrote:
> James Kuyper<jameskuyper@verizon.net>  wrote:
>>
>> #include<stdlib.h>
>> #define TRICAT(a, b, c) a ## b ## c
>> #define CHAR(a, b, c) TRICAT(a, b, c)
>>
>> #define CASE1 x
>>
> ...
>>      case CHAR('
>>          , CASE1, '
>>          ): break;
>
> Nice try, but no cigar.  The ## operator requires that the result be a
> valid pp-token and, depending on the order in which the operators are
> evaluated, you either end up with 'x or x', neither of which are valid
> pp-tokens.

So if we are concatenating 3 pp-tokens, not only do the individual items (a,b,c) 
and the final concatenation need to be valid pp-tokens, but also all potential 
_intermediates_, as determined by the unspecified processor order. That seems a 
needless and complicating restriction.

If I understand correctly, CHAR(<,<,=) will work because both << and <= are 
valid pp-tokens, but CHAR(., ., .) will not because .. isn't.

Finally the result of CHAR(%:, %, :) is undefined/unspecified, since order of 
concatenation determines whether the intermediate is %:% ## : or %: ## %: where 
%:% is not a pp-token.  I noticed that CHAR(C,3,_) is only required to work 
because 3_ is a valid pp-number!

It seems that the rule could be replaced by a greedy algorithm that concatenates 
all ##-connected pp-tokens before requiring a pp-token result.  As far as I can 
see such replacement would have no incompatibility with the current standard and 
would add little additional wording and processing.  It would simplify the 
concept by not relying on happenstance intermediates as noted above.

Thad

[toc] | [prev] | [next] | [standalone]


#12901

FromHarald van Dijk <truedfx@gmail.com>
Date2011-11-08 09:01 -0800
Message-ID<e5604f05-1376-4a92-9c17-51cc92b3ff0b@d17g2000yql.googlegroups.com>
In reply to#12859
On Nov 7, 11:53 pm, lawrence.jo...@siemens.com wrote:
> James Kuyper <jameskuy...@verizon.net> wrote:
> > #include <stdlib.h>
> > #define TRICAT(a, b, c) a ## b ## c
> > #define CHAR(a, b, c) TRICAT(a, b, c)
>
> > #define CASE1 x
>
> ...
> >     case CHAR('
> >         , CASE1, '
> >         ): break;
>
> Nice try, but no cigar.  The ## operator requires that the result be a
> valid pp-token and, depending on the order in which the operators are
> evaluated, you either end up with 'x or x', neither of which are valid
> pp-tokens.

Even if ## were redefined so that intermediate results of a ## b ## c
are ignored, the behaviour is explicitly undefined.

6.4:
preprocessing-token:
  [...]
  each non-white-space character that cannot be one of the above

6.4p3:
If a ' or a " character matches the last category, the behavior is
undefined.

[toc] | [prev] | [next] | [standalone]


#12904

FromJames Kuyper <jameskuyper@verizon.net>
Date2011-11-08 12:15 -0500
Message-ID<4EB963BA.1020800@verizon.net>
In reply to#12901
On 11/08/2011 12:01 PM, Harald van Dijk wrote:
> On Nov 7, 11:53 pm, lawrence.jo...@siemens.com wrote:
>> James Kuyper <jameskuy...@verizon.net> wrote:
>>> #include <stdlib.h>
>>> #define TRICAT(a, b, c) a ## b ## c
>>> #define CHAR(a, b, c) TRICAT(a, b, c)
>>
>>> #define CASE1 x
>>
>> ...
>>>     case CHAR('
>>>         , CASE1, '
>>>         ): break;
>>
>> Nice try, but no cigar.  The ## operator requires that the result be a
>> valid pp-token and, depending on the order in which the operators are
>> evaluated, you either end up with 'x or x', neither of which are valid
>> pp-tokens.
> 
> Even if ## were redefined so that intermediate results of a ## b ## c
> are ignored, the behaviour is explicitly undefined.
> 
> 6.4:
> preprocessing-token:
>   [...]
>   each non-white-space character that cannot be one of the above
> 
> 6.4p3:
> If a ' or a " character matches the last category, the behavior is
> undefined.

Yes, I forgot about that item, too.

[toc] | [prev] | [next] | [standalone]


#12864

FromAndrey Vul <andrey.vul@gmail.com>
Date2011-11-07 17:32 -0800
Message-ID<3a4820b7-ea0d-43bf-a158-807d4c0b2294@l19g2000yqc.googlegroups.com>
In reply to#12855
On Nov 7, 3:07 pm, James Kuyper <jameskuy...@verizon.net> wrote:
> On 11/07/2011 02:11 PM, Andrey Vul wrote:
>
> > On Nov 7, 1:59 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> >> On 11/ 8/11 07:53 AM, Andrey Vul wrote:
>
> >>> To stringify pp-constants, we use #foo notation.
> >>> Is there a method of charifying constants defined on the preprocessor
> >>> level, assuming the precondition of length being 1 is true?
>
> I presume there's some reason why the constants cannot, themselves, be
> defined as character constants?
>
> >>> That is, does there exist a pp-builtin CHARIFY such that CHARIFY(x) =
> >>> 'x' ?
>
> >> Something like
>
> >> #define CHAR(x) #x [0]
>
> > Can't be used inside switch.
>
> There's no simple way I can think of to define a macro that generates a
> character constant whose value depends upon the expansion of another
> macro. I did, however, manage to come up with this ugly monstrosity,
> which cannot possibly qualify as "simple", which I've inserted into some
> test code:
>
> #include <stdlib.h>
> #define TRICAT(a, b, c) a ## b ## c
> #define CHAR(a, b, c) TRICAT(a, b, c)
>
> #define CASE1 x
>
> int main(int argc, char *argv[])
> {
>     if(argc <= 1)
>         return EXIT_FAILURE;
>     switch (*argv[1])
>     {
>     case CHAR('
>         , CASE1, '
>         ): break;
>     default:
>         return EXIT_SUCCESS;
>     }
>     return EXIT_FAILURE;
>
> }
>
> The key thing that makes this work is that ' immediately followed by a
> newline is not recognized as any other type of pre-processing token, so
> it counts as a preprocessing token of it's own, under the classification
> "each non-white-space character that cannot be one of the above" (6.4p1).
>
> The two-level expansion allows CASE1 to be expanded to x before being
> concatenated with the ' tokens.
>

That looks like it shouldn't even compile!

In the end, I figured it's best to define as a char in the first place
and define the string as { 'f', 'o', 'o', 'b', 'a', 'r', ... } instead
of "foo" "bar" "...".

It's not like I'm making use of null-termination in the string
anyways.

[toc] | [prev] | [next] | [standalone]


#12869

FromJames Kuyper <jameskuyper@verizon.net>
Date2011-11-07 21:17 -0500
Message-ID<j9a3fv$ou0$1@dont-email.me>
In reply to#12864
On 11/07/2011 08:32 PM, Andrey Vul wrote:
> On Nov 7, 3:07�pm, James Kuyper <jameskuy...@verizon.net> wrote:
...
>> There's no simple way I can think of to define a macro that generates a
>> character constant whose value depends upon the expansion of another
>> macro. I did, however, manage to come up with this ugly monstrosity,
>> which cannot possibly qualify as "simple", which I've inserted into some
>> test code:
>>
>> #include <stdlib.h>
>> #define TRICAT(a, b, c) a ## b ## c
>> #define CHAR(a, b, c) TRICAT(a, b, c)
>>
>> #define CASE1 x
>>
>> int main(int argc, char *argv[])
>> {
>> � � if(argc <= 1)
>> � � � � return EXIT_FAILURE;
>> � � switch (*argv[1])
>> � � {
>> � � case CHAR('
>> � � � � , CASE1, '
>> � � � � ): break;
>> � � default:
>> � � � � return EXIT_SUCCESS;
>> � � }
>> � � return EXIT_FAILURE;
>>
>> }
>>
>> The key thing that makes this work is that ' immediately followed by a
>> newline is not recognized as any other type of pre-processing token, so
>> it counts as a preprocessing token of it's own, under the classification
>> "each non-white-space character that cannot be one of the above" (6.4p1).
>>
>> The two-level expansion allows CASE1 to be expanded to x before being
>> concatenated with the ' tokens.
>>
> 
> That looks like it shouldn't even compile!

It does compile, and works as intended - with gcc, with maximal
conformance and warning levels turned on. However, whether or not it's
required to compile is, at best, ambiguous. See Lawrence Jone's message
on this same thread - he's a fairly authoritative source, which doesn't
mean he's necessarily right - but I wouldn't recommend betting a lot of
money against him.

I'm curious - is there any specific feature that bothers you about that
code, other than the issue that Larry raised?

> In the end, I figured it's best to define as a char in the first place
> and define the string as { 'f', 'o', 'o', 'b', 'a', 'r', ... } instead
> of "foo" "bar" "...".

Yes, that's by far the better approach, even if there were no ambiguity
about my "solution".
-- 
James Kuyper

[toc] | [prev] | [next] | [standalone]


#12853

FromAndrey Vul <andrey.vul@gmail.com>
Date2011-11-07 11:08 -0800
Message-ID<6a676bb7-78fe-426a-a5d5-0e7d2e0bd257@h30g2000pro.googlegroups.com>
In reply to#12851
On Nov 7, 1:59 pm, Ian Collins <ian-n...@hotmail.com> wrote:
> On 11/ 8/11 07:53 AM, Andrey Vul wrote:
>
> > To stringify pp-constants, we use #foo notation.
> > Is there a method of charifying constants defined on the preprocessor
> > level, assuming the precondition of length being 1 is true?
> > That is, does there exist a pp-builtin CHARIFY such that CHARIFY(x) =
> > 'x' ?
>
> Something like
>
> #define CHAR(x) #x [0]

Can't be used inside switch or anything else requiring a const
expression.

[toc] | [prev] | [next] | [standalone]


#12861

FromPeter Nilsson <airia@acay.com.au>
Date2011-11-07 16:46 -0800
Message-ID<4c5d4452-89a7-400b-95e9-5b9e63f274f9@k38g2000pro.googlegroups.com>
In reply to#12850
Andrey Vul <andrey....@gmail.com> wrote:
> To stringify pp-constants, we use #foo notation.
> Is there a method of charifying constants defined
> on the preprocessor level, assuming the precondition
> of length being 1 is true? That is, does there exist
> a pp-builtin CHARIFY such that CHARIFY(x) = 'x' ?

This is a good example of a question on a possible
solution to an unstated problem. As James Juyper asks,
what is the real problem that you're trying to solve?

In short, if you're already hardcoding x, why can't
you hardcode 'x'?

There are ways of synchronising elements using the
preprocessor. But different methods have different
advantages and disadvantages. The following will work
for some characters but not for others...

  #define char_x 'x'
  #define char_y 'y'

  #define CHARIFY(x) char_ ## x

  switch (blah)
  {
    case CHARIFY(x):
      ..
    case CHARIFY(y):
      ..
  }

--
Peter

[toc] | [prev] | [standalone]


Back to top | Article view | comp.lang.c


csiph-web