Velocity Reviews

Velocity Reviews (http://www.velocityreviews.com/forums/index.php)
-   C Programming (http://www.velocityreviews.com/forums/f42-c-programming.html)
-   -   A variation of # (http://www.velocityreviews.com/forums/t805665-a-variation-of.html)

Andrey Vul 11-07-2011 06:53 PM

A variation of #
 
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' ?

Ian Collins 11-07-2011 06:59 PM

Re: A variation of #
 
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

Andrey Vul 11-07-2011 07:08 PM

Re: A variation of #
 
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.

Andrey Vul 11-07-2011 07:11 PM

Re: A variation of #
 
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.

James Kuyper 11-07-2011 08:07 PM

Re: A variation of #
 
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.

James Kuyper 11-07-2011 11:31 PM

Re: A variation of #
 
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.


Peter Nilsson 11-08-2011 12:46 AM

Re: A variation of #
 
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

Andrey Vul 11-08-2011 01:32 AM

Re: A variation of #
 
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.



James Kuyper 11-08-2011 02:17 AM

Re: A variation of #
 
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

Thad Smith 11-08-2011 02:51 AM

Re: A variation of #
 
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


All times are GMT. The time now is 05:27 AM.

Powered by vBulletin®. Copyright ©2000 - 2014, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.