'if' statement to control switch case

J

John

Hi Folks,

I'm experimenting a little with creating a custom CEdit control so that
I can decide on what the user is allowed to type into the control. I
started off only allowing floating point numbers then added support for
putting in lat/lon coordinates.

I tried this little piece of code inside the OnChar function but
compiler complained about missing ';' after "case _T('W'):"

switch(nChar)
{
if(m_bLATLON) // if latlon then no negs and 4 extra chars.
{
case _T('N'):
case _T('E'):
case _T('S'):
case _T('W'):
}
else
case _T('-'); // if not latlon we are allowed negs.

case _T('.'): // allowed characters on both cases.
case _T('0'):
case _T('1'):
case _T('2'):
case _T('3'):
case _T('4'):
case _T('5'):
case _T('6'):
case _T('7'):
case _T('8'):
case _T('9'):
case _T('\b'):
break;

default:
return;
}

now I could just have the 'if' statement first and then have two
seperate switch statements but i would rather do the method above as it
'looks' more elegante :eek:)
Is there some magic way to do what I am wanting or does it just break
the rules of c++ ?

Cheers,

John.
 
V

Victor Bazarov

John said:
Hi Folks,

I'm experimenting a little with creating a custom CEdit control so
that I can decide on what the user is allowed to type into the
control. I started off only allowing floating point numbers then
added support for putting in lat/lon coordinates.

I tried this little piece of code inside the OnChar function but
compiler complained about missing ';' after "case _T('W'):"

switch(nChar)
{
if(m_bLATLON) // if latlon then no negs and 4 extra chars.
{
case _T('N'):
case _T('E'):
case _T('S'):
case _T('W'):

Have you tried inserting the semicolon here?
}
else
case _T('-'); // if not latlon we are allowed negs.

What's the semicolon doing here?
case _T('.'): // allowed characters on both cases.
case _T('0'):
case _T('1'):
case _T('2'):
case _T('3'):
case _T('4'):
case _T('5'):
case _T('6'):
case _T('7'):
case _T('8'):
case _T('9'):
case _T('\b'):
break;

default:
return;
}

Next time, do please post the real code that gives you trouble.
now I could just have the 'if' statement first and then have two
seperate switch statements but i would rather do the method above as
it 'looks' more elegante :eek:)
Is there some magic way to do what I am wanting or does it just break
the rules of c++ ?

I think it does break the rules, but you haven't taken it to the full
extreme yet.

V
 
J

John

Victor said:
Have you tried inserting the semicolon here?

Yes, and the error goes away but the functionality of the code doesn't
work i.e. regardless of whether m_bLATLON is true/false it never
acknowledges any of the cases.
What's the semicolon doing here?

mmmhhh not sure - its not in my code so must just be a typo.
Next time, do please post the real code that gives you trouble.

This is the real code - it just had that one typo. I didn't want to post
the entire OnChar function that I overode as I thought someone would
see that it was a CEdit function and flame me for posting in the wrong
group!
 
V

Victor Bazarov

[..]

OK, this is what I tried. It compiles (on both VC++ and Comeau),
and the effect (on VC++) is that the 'if' is essentially ignored:

#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
switch (argc)
{
if (argv[0][0] == 'C') {
case 0:
case 1:
cout << "0 or 1\n";
break;
}
else {
case 2:
cout << "2\n";
break;
default:
cout << "3 or more\n";
}
}
}

Try it.

V
 
P

Pete Becker

Victor said:
[..]

OK, this is what I tried. It compiles (on both VC++ and Comeau),
and the effect (on VC++) is that the 'if' is essentially ignored:

Indeed. There's no way that the control flow can reach it, since the
switch statement jumps to a case label, and there's no label before the if.

--

-- Pete
Roundhouse Consulting, Ltd. (www.versatilecoding.com)
Author of "The Standard C++ Library Extensions: a Tutorial and
Reference." (www.petebecker.com/tr1book)
 
M

mlimber

Hi Folks,

I'm experimenting a little with creating a custom CEdit control so that
I can decide on what the user is allowed to type into the control. I
started off only allowing floating point numbers then added support for
putting in lat/lon coordinates.

I tried this little piece of code inside the OnChar function but
compiler complained about missing ';' after "case _T('W'):"

switch(nChar)
{
if(m_bLATLON) // if latlon then no negs and 4 extra chars.
{
case _T('N'):
case _T('E'):
case _T('S'):
case _T('W'):
}
else
case _T('-'); // if not latlon we are allowed negs.

case _T('.'): // allowed characters on both cases.
case _T('0'):
case _T('1'):
case _T('2'):
case _T('3'):
case _T('4'):
case _T('5'):
case _T('6'):
case _T('7'):
case _T('8'):
case _T('9'):
case _T('\b'):
break;

default:
return;

}

now I could just have the 'if' statement first and then have two
seperate switch statements but i would rather do the method above as it
'looks' more elegante :eek:)

....and bloody confusing. Duff's Device did a similar trick for the
purposes of optimization, but I don't think optimization is your major
concern here (or at least it shouldn't be at this stage in your
development). Prefer to go with a straightforward, readable approach
even if it's less "cool". As Kernighan, co-creator of C, said,
"Debugging is twice as hard as writing the code in the first place.
Therefore, if you write the code as cleverly as possible, you are, by
definition, not smart enough to debug it." That seems to apply
directly here.

Cheers! --M
 
J

Jonas

John said:
Hi Folks,

I'm experimenting a little with creating a custom CEdit control so that I
can decide on what the user is allowed to type into the control. I started
off only allowing floating point numbers then added support for putting in
lat/lon coordinates.

I tried this little piece of code inside the OnChar function but compiler
complained about missing ';' after "case _T('W'):"

switch(nChar)
{
if(m_bLATLON) // if latlon then no negs and 4 extra chars.
{
case _T('N'):
case _T('E'):
case _T('S'):
case _T('W'):
}
else
case _T('-'); // if not latlon we are allowed negs.

case _T('.'): // allowed characters on both cases.
case _T('0'):
case _T('1'):
case _T('2'):
case _T('3'):
case _T('4'):
case _T('5'):
case _T('6'):
case _T('7'):
case _T('8'):
case _T('9'):
case _T('\b'):
break;

default:
return;
}

Wrap an if around your cases like that will not produce the desired effect.
Try conditionally returning or breaking depending on the value of m_bLATLON
instead:

switch(nChar)
{
case _T('N'):
case _T('E'):
case _T('S'):
case _T('W'):
if(!m_bLATLON)
return;
break;

case _T('-'):
if(m_bLATLON)
return;
break;

case _T('.'):
case _T('0'):
case _T('1'):
case _T('2'):
case _T('3'):
case _T('4'):
case _T('5'):
case _T('6'):
case _T('7'):
case _T('8'):
case _T('9'):
case _T('\b'):
break;

default:
return;
}
 
J

John

Jonas said:
Wrap an if around your cases like that will not produce the desired effect.
Try conditionally returning or breaking depending on the value of m_bLATLON
instead:

switch(nChar)
{
case _T('N'):
case _T('E'):
case _T('S'):
case _T('W'):
if(!m_bLATLON)
return;
break;

case _T('-'):
if(m_bLATLON)
return;
break;

case _T('.'):
case _T('0'):
case _T('1'):
case _T('2'):
case _T('3'):
case _T('4'):
case _T('5'):
case _T('6'):
case _T('7'):
case _T('8'):
case _T('9'):
case _T('\b'):
break;

default:
return;
}

Hey Jonas,

thanks for the reply - I can't do it the way you wrote though.

I need all of the default cases too (. 0 1 2 3 ....etc) depending on the
m_bLATLON variable i wanted to extend them, not blank them out totally.


To the rest of the guys that replied - cheers for the help. I've just
decided to do it the long way and duplicate/customize the switch based
on an 'if-else' test on the m_bLATLON var.

Thanks everybody,

John.
 
G

Greg Comeau

I'm experimenting a little with creating a custom CEdit control so that
I can decide on what the user is allowed to type into the control. I
started off only allowing floating point numbers then added support for
putting in lat/lon coordinates.

I tried this little piece of code inside the OnChar function but
compiler complained about missing ';' after "case _T('W'):"

switch(nChar)
{
if(m_bLATLON) // if latlon then no negs and 4 extra chars.
{
case _T('N'):
case _T('E'):
case _T('S'):
case _T('W'):

Labels in C++ and C need to target statements. A case establishes
a label. So you need at least a semicolon here, since that brings
forth a null statement.
}
else
case _T('-'); // if not latlon we are allowed negs.

Same here. You need at least a : and ;
case _T('.'): // allowed characters on both cases.
case _T('0'):
case _T('1'):
case _T('2'):
case _T('3'):
case _T('4'):
case _T('5'):
case _T('6'):
case _T('7'):
case _T('8'):
case _T('9'):
case _T('\b'):
break;

default:
return;
}

now I could just have the 'if' statement first and then have two
seperate switch statements but i would rather do the method above as it
'looks' more elegante :eek:)
Is there some magic way to do what I am wanting or does it just break
the rules of c++ ?

The fixed above should allow it to compile.

However, then you run into other problems, to wit,
that the if statement never executes as an if statement
(because it starts somewhere it will never get executed as such).
Your elegance (which is in the eye of the beholder) is too clever
for your own good.

That said, hoisting the if into at least 2 of the groups seems to fit,
but it's unclear what you are really trying to do, so that may be
misguided until you tell us.
 
G

Greg Comeau

thanks for the reply - I can't do it the way you wrote though.

I need all of the default cases too (. 0 1 2 3 ....etc) depending on the
m_bLATLON variable i wanted to extend them, not blank them out totally.

Probably you can use it if you never the test Jonas shows and
emit errors instead of the return, but it's still unclear what
you're doing. As....
To the rest of the guys that replied - cheers for the help. I've just
decided to do it the long way and duplicate/customize the switch based
on an 'if-else' test on the m_bLATLON var.

.... yes, actually it looks like you combined at least two distinct
things into one, at least as you've presented it. I mean,
can one really enter N55.W-? :)
 
O

Old Wolf

I tried this little piece of code inside the OnChar function but
compiler complained about missing ';' after "case _T('W'):"

Assuming _T(X) is defined to produce X or LX.
switch(nChar)
{
if(m_bLATLON) // if latlon then no negs and 4 extra chars.
{
case _T('N'):
case _T('E'):
case _T('S'):
case _T('W'):
}

The syntax of labels is that a label must be followed by a
statement (or another label). If you stick a semicolon after
the case 'W' line then it would compile.
else
case _T('-'); // if not latlon we are allowed negs.

This should fail to compile; a case label must be followed by
a colon.
case _T('.'): // allowed characters on both cases.
case _T('0'):

Note that even if m_BLATON is false, the code in the cases
of 'N','S' etc. will still execute, because the switch causes
control to jump to the case label, by-passing the if() statement.

If you fall through from case 'W', I don't know whether case '-'
will be entered! I can't find any text in the standard talking
about this, and in the example I tried, case '-' was executed
regardless of the setting of m_BLATON.
 
J

James Kanze

Assuming _T(X) is defined to produce X or LX.
The syntax of labels is that a label must be followed by a
statement (or another label). If you stick a semicolon after
the case 'W' line then it would compile.
This should fail to compile; a case label must be followed by
a colon.
Note that even if m_BLATON is false, the code in the cases
of 'N','S' etc. will still execute, because the switch causes
control to jump to the case label, by-passing the if() statement.
If you fall through from case 'W', I don't know whether case '-'
will be entered! I can't find any text in the standard talking
about this, and in the example I tried, case '-' was executed
regardless of the setting of m_BLATON.

The switch is effectively a goto, so as you say, the if is never
executed (and the switch can reach any of the case labels,
regardless of the state of m_bLATLON). As for falling through
from `case _T('W'):', you encounter an else. It's hard to
imagine an implementation where you didn't then jump around the
else part. Interestingly enough, however, the actual wording in
C++ standard seems to require the test a second time: it says
quite clearly that "If the else part of the selection statement
is present and the condition yields false, the second
substatement is executed." I suspect that this is not
intentional (nor the intent); this would require that the
compiler implement "if (x) a ; else b;" as "if (x) a; if(!x) b;"
(I'm pretty sure that no compiler does this, and that if the if
statement is not entered via the if, execution will continue
until the end of whichever part is entered, and then skip the
other part.)

FWIW: when I first started programming in C (and was still
young, and thought it cool to write code that no one else could
understand), I once wrote something like:

switch ( category( *p ) )
{
/* ... */
case CH_DOT :
if ( isdigit( *(p+1) ) ) {
case CH_NUMBER :
scanNumber( p ) ;
} else {
Case CH_PUNCT :
scanPunct( p ) ;
}
break ;
/* ... */
}

It worked fine, but I pity the poor guy who had to maintain it.
 
R

red floyd

John said:
I tried this little piece of code inside the OnChar function but
compiler complained about missing ';' after "case _T('W'):"

switch(nChar)
{
if(m_bLATLON) // if latlon then no negs and 4 extra chars.
{
case _T('N'):
case _T('E'):
case _T('S'):
case _T('W'):
}
else
case _T('-'); // if not latlon we are allowed negs.

case _T('.'): // allowed characters on both cases.
case _T('0'):
case _T('1'):
case _T('2'):
case _T('3'):
case _T('4'):
case _T('5'):
case _T('6'):
case _T('7'):
case _T('8'):
case _T('9'):
case _T('\b'):
break;

default:
return;
}

now I could just have the 'if' statement first and then have two
seperate switch statements but i would rather do the method above as it
'looks' more elegante :eek:)

It doesn't look more elegant to me. It looks horribly kludged and
unreadable.
Is there some magic way to do what I am wanting or does it just break
the rules of c++ ?

All I know is that if you worked for me, and you wrote code like that,
you'd get exactly one warning, and the next time you'd be fired.

I'm a big fan of what I call the "X-abilities": Readability, Scalability
and Maintainability. Your sample code fails at least two of the three.
 
G

Greg Comeau

... the actual wording in
C++ standard seems to require the test a second time: it says
quite clearly that "If the else part of the selection statement
is present and the condition yields false, the second
substatement is executed." I suspect that this is not
intentional (nor the intent); this would require that the
compiler implement "if (x) a ; else b;" as "if (x) a; if(!x) b;"
(I'm pretty sure that no compiler does this, and that if the if
statement is not entered via the if, execution will continue
until the end of whichever part is entered, and then skip the
other part.)

We're probably OT from the OPs question, but I'm
unclear what you mean. Do you mean the words should have
used "otherwise" or something like that (myself, now that
I read the words, I'd have preferred "only" or something like
that too probably as well as otherwise).
 
J

Jonas

John said:
Hey Jonas,

thanks for the reply - I can't do it the way you wrote though.

I need all of the default cases too (. 0 1 2 3 ....etc) depending on the
m_bLATLON variable i wanted to extend them, not blank them out totally.

They are still considered. The if(!m_bLATLON) test is only done in case
nChar is 'N', 'S', 'E' or 'W', and the if(m_bLATLON) only if nChar is '-'.
For any other value of nChar, the cases '.', '0' etc are tested.

In other words,

if m_bLATLON == TRUE, then the switch above returns unless nChar is in
{ N, S, W, E, ., 0, ..., 9, \b}
if m_bLATLON == FALSE, then the switch above returns unless nChar is in
{ -, ., 0, ..., 9, \b}

Was this not what you intended?
 
O

Old Wolf

The switch is effectively a goto, so as you say, the if is never
executed (and the switch can reach any of the case labels,
regardless of the state of m_bLATLON). As for falling through
from `case _T('W'):', you encounter an else. It's hard to
imagine an implementation where you didn't then jump around the
else part.

Output of the following code:
g++,gcc 3.4.1: 1 2 1 2
g++,gcc 4.0.1: 1 1

Should this be considered a bug in the earlier version (or both)?

#include <stdio.h>

void foo(int x)
{
switch(1)
{
if (x) {
case 1: printf("1 ");
}
else
case 2: printf("2 ");
}
}

int main()
{
foo(1);
foo(0);
puts("");
return 0;
}
 
F

Fudd

red said:
It doesn't look more elegant to me. It looks horribly kludged and
unreadable.

Are you blind or something red floyd? The OPs code is readable (just not
correct). Its people like you that remind me why I never really post
any questions to newsgroups. You do get a lot of useful answers (like
previous ones to OPs question) but then along comes a little ponce like
you with your useless two cents! Where in the original question did it
ask you about your opinion on elegance of the code huh?
All I know is that if you worked for me, and you wrote code like that,
you'd get exactly one warning, and the next time you'd be fired.

I'm a big fan of what I call the "X-abilities": Readability, Scalability
and Maintainability. Your sample code fails at least two of the three.

And I am a big fan of answering the question asked and not posting a
load of crap. If you read the OPs original question he said he was
"experimenting". It doesn't imply anywhere in the message that he is
writing code that would need to fit your shitty "X-abilities" rules. I
remember now why I also canceled my IET membership - too many management
twats in charge of young enthusiastic people with good 'developing'
skills that need nurturing and not bollockings just because you can (you
strike me as one of they management types!).

Do me a favor - next time you see your mom, give her a slap ;o)


// FUDD \\
 
R

red floyd

Fudd said:
Are you blind or something red floyd? The OPs code is readable (just not
correct). Its people like you that remind me why I never really post
any questions to newsgroups. You do get a lot of useful answers (like
previous ones to OPs question) but then along comes a little ponce like
you with your useless two cents! Where in the original question did it
ask you about your opinion on elegance of the code huh?

Fine. Look at it one year from now and figure out what it's supposed to
do. Especially if there's a bug related to it.

Oh, and personal attacks like that really make me want to pay attention
to what you say. After 20 years of developing, debugging and
maintaining C and C++, I would loudly proclaim (and have done so -- in
the presence of said author) that the anyone who put code like that into
production should be shot.
 
J

John

Jonas said:
They are still considered. The if(!m_bLATLON) test is only done in case
nChar is 'N', 'S', 'E' or 'W', and the if(m_bLATLON) only if nChar is '-'.
For any other value of nChar, the cases '.', '0' etc are tested.

In other words,

if m_bLATLON == TRUE, then the switch above returns unless nChar is in
{ N, S, W, E, ., 0, ..., 9, \b}
if m_bLATLON == FALSE, then the switch above returns unless nChar is in
{ -, ., 0, ..., 9, \b}

Was this not what you intended?


Jonas,

Sorry I was wrong - I misread the post. Your code does do what I wanted
it to do.

Cheers,

John.
 
J

James Kanze

Output of the following code:
g++,gcc 3.4.1: 1 2 1 2
g++,gcc 4.0.1: 1 1
Should this be considered a bug in the earlier version (or both)?

I don't think the standard is actually that clear about it, see
my response to Greg. At any rate, I wouldn't send in a bug
report until the question has been discussed in comp.std.c++.

Frankly, I wouldn't send in a bug report even then. I don't
care what it does in such cases:). But once, in the distant
past, I did write code which expected the behavior of g++ 4.0.1;
it seems the most "intuitive", at least for someone familiar
with machine code, and how the basic flow control structures map
to it.
#include <stdio.h>
void foo(int x)
{
switch(1)
{
if (x) {
case 1: printf("1 ");
}
else
case 2: printf("2 ");
}
}
int main()
{
foo(1);
foo(0);
puts("");
return 0;
}

It's an interesting example. Apparently, g++ 3.x recognizes
that the if will never be executed, and removes it (and all
associated code). Change the switch argument to a variable, and
put an additional case label in front of it, and g++ 3.x (3.4.0,
anyway) also outputs "1 1 ", even though the switch control
variable is always 1.

I wouldn't be surprised if the difference between 3.x and 4.x
here isn't the result of a bug fix; that someone complained, and
that the authors of g++ considered it an error, and added a
check to inhibit the optimization, or do it slightly
differently, so as to get "1 1 ". Intuitively, it does seem
rather "wrong" that a single pass through can execute code from
both the then and the else branch. (I suppose one could argue
that the standard doesn't really say what should happen, and in
cases where the standard doesn't specify the behavior, it is
undefined behavior. But that seems a bit over the limit to me.)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,582
Members
45,065
Latest member
OrderGreenAcreCBD

Latest Threads

Top