Removing "if (a = b)" warning

S

Stephen

Is there a standard way to remove the warning that a C compiler might
produce from the statement:

if (a = b) {}

I don't want to do:

if ((a = b) != 0) {}

Because my "a = b" is actually contained in a macro that might be used
as a statement or as an expression within (for example) an "if"
statement.

If it makes any difference, here's exactly what I'm trying to do. In
order to get around a limitation of a particular C compiler that will
not allow p++ (or any other pointer arithmetic) to work correctly across
64KB boundaries, I have come up with a few macros, one of which is:

#define FARPTR_INC(p) p=(void far *)(((ULONG)(p))+sizeof(*(p)))

Now I can do:

UBYTE far *pb;
UWORD far *pw;
ULONG far *pl;
FARPTR_INC(pb); // Replacement for: pb++; (adds 1 to address)
FARPTR_INC(pw); // Replacement for: pw++; (adds 2 to address)
FARPTR_INC(pl); // Replacement for: pl++; (adds 4 to address)

I can also do:

func(FARPTR_INC(p)); // Replacement for: func(p++);

But if I do:

if (FARPTR_INC(p)) {}

Then I get a warning since the compiler is justifiably taking the view
that I might have missed an equals sign and accidentally turned an
equality comparison into an assignment.

[Please excuse the C++ commenting style in my C code. I know you're all
C purists in c.l.c, and rightly so, but I choose to use C++ comments in
my C code because every C compiler I use (or probably ever will use now)
handles it ;-)
.... oh, and stuff like UBYTE is "#define UBYTE unsigned char" etc.]
 
J

Jordan Abel

Is there a standard way to remove the warning that a C compiler might
produce from the statement:

if (a = b) {}

I don't want to do:

if ((a = b) != 0) {}

Because my "a = b" is actually contained in a macro that might be used
as a statement or as an expression within (for example) an "if"
statement.

If it's from a macro the macro should have its own parentheses to avoid
precedence problems anyway, say...
If it makes any difference, here's exactly what I'm trying to do. In
order to get around a limitation of a particular C compiler that will
not allow p++ (or any other pointer arithmetic) to work correctly across
64KB boundaries, I have come up with a few macros, one of which is:

#define FARPTR_INC(p) p=(void far *)(((ULONG)(p))+sizeof(*(p)))

#define FARPTR_INC(p) ((p)=(void far *)(((ULONG)(p))+sizeof(*(p))))

This fits with the traditional way of avoiding the error, which is
to do if((a = b)).
Now I can do:

UBYTE far *pb;
UWORD far *pw;
ULONG far *pl;
FARPTR_INC(pb); // Replacement for: pb++; (adds 1 to address)
FARPTR_INC(pw); // Replacement for: pw++; (adds 2 to address)
FARPTR_INC(pl); // Replacement for: pl++; (adds 4 to address)

I can also do:

func(FARPTR_INC(p)); // Replacement for: func(p++);

no it's not. it replaces func(++p) - you'd need the following macro
for p++:

#define FARPTR_POSTINC(p) (((p)=(void far*)((ULONG)(p)+sizeof \
*(p))), (void far *)((ULONG)(p)-sizeof *(p)))
But if I do:

if (FARPTR_INC(p)) {}

Then I get a warning since the compiler is justifiably taking the view
that I might have missed an equals sign and accidentally turned an
equality comparison into an assignment.

[Please excuse the C++ commenting style in my C code. I know you're all
C purists in c.l.c, and rightly so, but I choose to use C++ comments in
my C code because every C compiler I use (or probably ever will use now)
handles it ;-)

And yet no pointer arithmetic?
... oh, and stuff like UBYTE is "#define UBYTE unsigned char" etc.]

Compiler doesn't handle typedefs either, i take it?
 
J

Jordan Abel

[stuff, see other message]

PS Incidentally, what makes you think you can safely do this? A "far pointer"
may not have an integer representation of which adding to it will result in the
next adjacent memory cell.

incidentally, try

#define PTR_ADD(a,i) (&(a))
#define PTR_SUB(a,i) PTR_ADD(a,-i)
#define PTR_EQP(a,i) ((p)=PTR_ADD(a,i))
#define PTR_EQM(a,i) ((p)=PTR_SUB(a,i))
#define PTR_PPX(p) PTR_EQP(a,1)
#define PTR_MMX(p) PTR_EQM(a,1)
#define PTR_XPP(p) (PTR_PPX(p),PTR_SUB(p,1))
#define PTR_XMM(p) (PTR_MMX(p),PTR_ADD(p,1))

More concise, don't require casting, and retain type-safety.

Incidentally, i'd ditch the crappy compiler if i were you.
 
M

Martin Ambuhl

Stephen said:
Is there a standard way to remove the warning that a C compiler might
produce from the statement:

if (a = b) {}

I don't want to do:

if ((a = b) != 0) {}

No *standard* way, since compilers are free to issue whatever warnings
they want. There is a *common* way:
if ((a = b)) { }
Because my "a = b" is actually contained in a macro that might be used
as a statement or as an expression within (for example) an "if"
statement.

I'm sure some others can parse that and make sense of it, but it's
beyond me.
#define FARPTR_INC(p) p=(void far *)(((ULONG)(p))+sizeof(*(p)))

If ULONG is an integral type (unsigned long, I suppose), you may be in
deep doo-doo converting a pointer to it. But I suppose you know your
implementation -- since 'far' and 'ULONG' are otherwise undefined
identifiers here. The details of the macros are unimportant for your
question, since
But if I do:
if (FARPTR_INC(p)) {}

this can be subjected to the same treatment:
if ((FARPTR_INC(p))) {}

Now, it has been reported before that some compilers from Borland do not
respond as wished to these parentheses. While that is not a sign of a
broken compiler (it's free to issue such warnings), ir is annoying.

... oh, and stuff like UBYTE is "#define UBYTE unsigned char" etc.]

You can do that if you wish. I prefer using 'unsigned char' when I mean
'unsigned char'. If the name made this an abstract or opaque type, it
might be a different story, but 'UCHAR' screams rather that the type
should be 'unsigned char.' If you *must* do this, consider a typedef
instead of a #define, though/
 
S

Stephen

Jordan Abel said:
If it's from a macro the macro should have its own parentheses to avoid
precedence problems anyway, say...

#define FARPTR_INC(p) ((p)=(void far *)(((ULONG)(p))+sizeof(*(p))))

This fits with the traditional way of avoiding the error, which is
to do if((a = b)).

Thanks for the quick reply.

I haven't tried this on the compiler in question yet (on wrong machine
at moment), but I tried it on another compiler and it doesn't help - it
still complains at: if ((a = b))
no it's not. it replaces func(++p) - you'd need the following macro
for p++:

#define FARPTR_POSTINC(p) (((p)=(void far*)((ULONG)(p)+sizeof \
*(p))), (void far *)((ULONG)(p)-sizeof *(p)))

Ahh, well spotted. I had been starting to wonder how to do
postinc/preinc (but only need one so far) but hadn't spotted that I had
documented my preinc attempt incorrectly.
[Please excuse the C++ commenting style in my C code. I know you're all
C purists in c.l.c, and rightly so, but I choose to use C++ comments in
my C code because every C compiler I use (or probably ever will use now)
handles it ;-)

And yet no pointer arithmetic?

None that cross 64KB boundaries.
... oh, and stuff like UBYTE is "#define UBYTE unsigned char" etc.]

Compiler doesn't handle typedefs either, i take it?

Oh I knew someone would say that ;-)

I've had difficulties in the past with typedef support. I'm sure I could
probably change it to a typedef now though. Old habits die hard.
PS Incidentally, what makes you think you can safely do this? A "far
pointer" may not have an integer representation of which adding to it
will result in the next adjacent memory cell.

These are macros dedicated to a specific compiler/platform. The casting
to ULONG does work, it's the only way around this problem without
resorting to assembler. The macros collapse to regular "p++" statements
on the better platforms.
incidentally, try
#define PTR_ADD(a,i) (&(a))


This, and your other examples, don't work on the affected compiler. The
implementation of might cross a 64KB boundary.
Incidentally, i'd ditch the crappy compiler if i were you.

It's actually highly regarded as the best compiler available for this
platform by far, and it's also the most expensive. The problem is that
its an embedded platform, and flat memory space beyond 64KB is
relatively new on this processor architecture, so compiler support for
the new far (flat) memory is not quite at its best yet.

Any other suggestions for how to stop the warning on: "if (a = b)" ?
 
S

Stephen

Martin said:
I'm sure some others can parse that and make sense of it, but it's
beyond me.

Sorry, my "Because..." line was a continuation of my "I don't want to
do:" line, with the example in the middle.
this can be subjected to the same treatment:
if ((FARPTR_INC(p))) {}

Now, it has been reported before that some compilers from Borland do not
respond as wished to these parentheses. While that is not a sign of a
broken compiler (it's free to issue such warnings), ir is annoying.

Hmm, as you'll see from my other reply this does not work, but
interestingly my quick test was on a Borland compiler. I'll need to get
back to my development machine and try it on the other compiler.
... oh, and stuff like UBYTE is "#define UBYTE unsigned char" etc.]

You can do that if you wish. I prefer using 'unsigned char' when I
mean
'unsigned char'. If the name made this an abstract or opaque type, it
might be a different story, but 'UCHAR' screams rather that the type
should be 'unsigned char.'

I NEVER use integral types throughout the code. It's too non-portable on
cross-platform code. I have come across platforms where char defaults to
32-bit and others where int is 8-bit. Hence the reason I create my own
"types". A UBYTE will be guaranteed 8-bit unsigned regardless of how
hard I have to hit the compiler. It also saves space - the embedded
targets often need other additional compiler specific qualifiers in
declarations and casts so some lines can get a bit long. I've even known
people to use U8, U16 etc. Plus: UBYTE, SBYTE, UWORD, SWORD, ULONG,
SLONG are all the same length (characters) so the code looks pretty :)
If you *must* do this, consider a typedef instead of a #define, though

Indeed, see my other reply :)
 
J

Jordan Abel

Jordan Abel said:
If it's from a macro the macro should have its own parentheses
to avoid precedence problems anyway, say...

#define FARPTR_INC(p) ((p)=(void far *)(((ULONG)(p))+sizeof(*(p))))

This fits with the traditional way of avoiding the error, which
is to do if((a = b)).

Thanks for the quick reply.

I haven't tried this on the compiler in question yet (on wrong
machine at moment), but I tried it on another compiler and it
doesn't help - it still complains at: if ((a = b))
no it's not. it replaces func(++p) - you'd need the following
macro for p++:

#define FARPTR_POSTINC(p) (((p)=(void far*)((ULONG)(p)+sizeof \
*(p))), (void far *)((ULONG)(p)-sizeof *(p)))

Ahh, well spotted. I had been starting to wonder how to do
postinc/preinc (but only need one so far) but hadn't spotted
that I had documented my preinc attempt incorrectly.
[Please excuse the C++ commenting style in my C code. I know
you're all C purists in c.l.c, and rightly so, but I choose
to use C++ comments in my C code because every C compiler I
use (or probably ever will use now) handles it ;-)

And yet no pointer arithmetic?

None that cross 64KB boundaries.

How, precisely, are 'far pointers' represented into unsigned
long? You've said that 64kb boundaries matter - i'd like to see
documentation for your platform
... oh, and stuff like UBYTE is "#define UBYTE unsigned char"
etc.]

Compiler doesn't handle typedefs either, i take it?

Oh I knew someone would say that ;-)

I've had difficulties in the past with typedef support. I'm
sure I could probably change it to a typedef now though. Old
habits die hard.
PS Incidentally, what makes you think you can safely do this? A
"far pointer" may not have an integer representation of which
adding to it will result in the next adjacent memory cell.

These are macros dedicated to a specific compiler/platform. The
casting to ULONG does work, it's the only way around this
problem without resorting to assembler. The macros collapse to
regular "p++" statements on the better platforms.

What i'm saying is that it will NOT work crossing a segment
boundary depending on how far pointers are actually represented.
incidentally, try
#define PTR_ADD(a,i) (&(a))


This, and your other examples, don't work on the affected
compiler. The implementation of might cross a 64KB
boundary.


And yours does not? Regardless, it's still much more readable to
use a single primitive that all your other macros are based on.
if you insist on doing it your way, use

#define PTR_ADD(a,i) ((void far *)((unsigned long)(a)+(i)*sizeof *(a)))

and all my other definitions.

and, perhaps most importantly, guard this definition with an
ifdef for your platform, and use the following for other
platforms:

#define PTR_ADD(a,i) ((a)+(i))

Even if you know your platform has a pointer representation where
the casting is safe, others might not.

also, if your compiler supports a [non-standard] typeof operator,
use it instead of void.
It's actually highly regarded as the best compiler available
for this platform by far, and it's also the most expensive. The
problem is that its an embedded platform, and flat memory space
beyond 64KB is relatively new on this processor architecture,
so compiler support for the new far (flat) memory is not quite
at its best yet.
Any other suggestions for how to stop the warning on: "if (a =
b)" ?

That was explained in my first post - add a pair of parens
surrounding the macro definition.
 
J

Jordan Abel

I NEVER use integral types throughout the code. It's too non-portable on
cross-platform code. I have come across platforms where char defaults to
32-bit and others where int is 8-bit. Hence the reason I create my own
"types". A UBYTE will be guaranteed 8-bit unsigned regardless of how
hard I have to hit the compiler. It also saves space - the embedded
targets often need other additional compiler specific qualifiers in
declarations and casts so some lines can get a bit long. I've even known
people to use U8, U16 etc. Plus: UBYTE, SBYTE, UWORD, SWORD, ULONG,
SLONG are all the same length (characters) so the code looks pretty :)

I'd recommend as a stylistic matter against switching between
c-style typenames and asm-style ones. if you must do this, consider
either ?BYTE ?WORD ?DWRD ?QWRD or ?CHAR ?SHRT ?LONG ?LLNG.

incidentally, on all systems where an 8-bit type is even possible at
all, that type will be [signed, unsigned] char.
 
S

Stephen

Jordan Abel said:
How, precisely, are 'far pointers' represented into unsigned
long? You've said that 64kb boundaries matter - i'd like to see
documentation for your platform

Trust me, it works on this platform.
What i'm saying is that it will NOT work crossing a segment
boundary depending on how far pointers are actually represented.

It does work across a 64KB boundary on this platform. Converting to
ULONG works. Arithmetic works on ULONG. Converting back to pointer
works.
This, and your other examples, don't work on the affected
compiler. The implementation of might cross a 64KB
boundary.


And yours does not?


Not in pointer land. My addition is in ULONG land, which works. Hence
the reason for temporary conversion to ULONG.
Regardless, it's still much more readable to
use a single primitive that all your other macros are based on.
if you insist on doing it your way, use

#define PTR_ADD(a,i) ((void far *)((unsigned long)(a)+(i)*sizeof *(a)))

You mean using it as: p = PTR_ADD(p,10); ?

Hmmm... I might do that, if it eliminates all possible errors.
That was explained in my first post - add a pair of parens
surrounding the macro definition.

And my reply indicated it didn't work, but as someone pointed out that
might be to do with the compiler I tested it on...
 
S

Stephen

Jordan Abel said:
I'd recommend as a stylistic matter against switching between
c-style typenames and asm-style ones. if you must do this, consider
either ?BYTE ?WORD ?DWRD ?QWRD or ?CHAR ?SHRT ?LONG ?LLNG.

Identifiers beginning with ? do not work on at least one of the
compilers I use regularly.
incidentally, on all systems where an 8-bit type is even possible at
all, that type will be [signed, unsigned] char.

In theory perhaps. But embedded compilers don't always meet ANSI
standards and usually deliberately break them for various reasons. I'm
sure one of the DSP environments I used defaulted "unsigned char" to
32-bit but then let you qualify the declaration if you insist on making
it 8-bit. The fun of embedded systems...
 
J

Jordan Abel

Trust me, it works on this platform.

what platform is it - i would like to see documentation anyway out
of my own curiosity
You mean using it as: p = PTR_ADD(p,10); ?

Hmmm... I might do that, if it eliminates all possible errors.

as ((p)=PTR_ADD(p,1)) - which iirc was the text of my PTR_PPX macro.
[PPX stands for "++x"]
And my reply indicated it didn't work, but as someone pointed out that
might be to do with the compiler I tested it on...

If that doesn't work nothing will. Tell your compiler to shut up
 
J

Jordan Abel

Identifiers beginning with ? do not work on at least one of the
compilers I use regularly.

? as a wildcard meaning in this case S or U.
incidentally, on all systems where an 8-bit type is even possible at
all, that type will be [signed, unsigned] char.

In theory perhaps. But embedded compilers don't always meet ANSI
standards and usually deliberately break them for various reasons. I'm
sure one of the DSP environments I used defaulted "unsigned char" to
32-bit but then let you qualify the declaration if you insist on making
it 8-bit. The fun of embedded systems...

and what is the sizeof(your 8-bit type)? 0.25?
 
S

Stephen

Jordan Abel said:
what platform is it - i would like to see documentation anyway out
of my own curiosity

Keil C51 for extended memory architecture 8051s.

The far pointer isn't a native type on the processor. It's essentially
an encapsulated (but documented) implementation for which the compiler
vendor has supplied suitable implementations of stuff like memcpy() etc.
but they don't offer proper support for objects across 64KB boundaries,
including pointer arithmetic across such boundaries.

The pointer is implemented as 24-bit big-endian and contains an offset
to distinguish it from other address spaces.

An address might be stored as: 0xAA 0xBB 0xCC
(although that doesn't correspond to address 0xAABBCC due to the
offset).

Conversion to ULONG would result in: 0x00AABBCC. The offset still exists
here. If you wanted a true ULONG representation of the address you have
to adjust by the offset (yet another macro!).

I do my inc/dec/add/sub on the ULONG to give: 0x00DDEEFF

Conversion back to pointer gives: 0xDD 0xEE 0xFF
as ((p)=PTR_ADD(p,1)) - which iirc was the text of my PTR_PPX macro.

Ahh, I see, you mean use separate macros for assignment and expressions.

I was trying to use one macro for all, but your way is probably the only
way to eliminate the warnings.

Thanks.
 
S

Stephen

Jordan Abel said:
? as a wildcard meaning in this case S or U.

Ahh, sorry, wooosh - missed the point entirely.

Time for some food I think...

I thought you meant prefixing them with ? to distinguish them from BYTE
as used in an assembler. The DWORD hatred is just a personal thing I
guess. I've always preferred LONG. Somehow when I see QWORD I usually
have to stop and think just how big it is, which increases the
likelihood of mistakes. And as for "short", to coin a phrase, how short
is a piece of string? I've seen shorts at 8, 16 or 32 bit and now
completely hate the word short :)

It should be taken out the back and short (groan...)

Incidentally, did you notice that you didn't use the word incidentally
in that last message?
 
T

Thad Smith

Stephen said:
Is there a standard way to remove the warning that a C compiler might
produce from the statement:

if (a = b) {}

I don't want to do:

if ((a = b) != 0) {}

Because my "a = b" is actually contained in a macro that might be used
as a statement or as an expression within (for example) an "if"
statement. ....
> I have come up with a few macros, one of which is:

#define FARPTR_INC(p) p=(void far *)(((ULONG)(p))+sizeof(*(p)))

Try:
#define FARPTR_INC(p) (p=(void far *)(((ULONG)(p))+sizeof(*(p))),p)

Thad
 
R

Randy Howard

Stephen wrote
(in article said:
The far pointer isn't a native type on the processor. It's essentially
an encapsulated (but documented) implementation for which the compiler
vendor has supplied suitable implementations of stuff like memcpy() etc.
but they don't offer proper support for objects across 64KB boundaries,
including pointer arithmetic across such boundaries.

The pointer is implemented as 24-bit big-endian and contains an offset
to distinguish it from other address spaces.

I just had a flashback to the old AHINCR driver hack in Windows
3.1 when using objects larger than 64KB. Thanks, uh, I think.
:)
 
K

Keith Thompson

Stephen said:
Ahh, sorry, wooosh - missed the point entirely.

Time for some food I think...

I thought you meant prefixing them with ? to distinguish them from BYTE
as used in an assembler. The DWORD hatred is just a personal thing I
guess. I've always preferred LONG. Somehow when I see QWORD I usually
have to stop and think just how big it is, which increases the
likelihood of mistakes. And as for "short", to coin a phrase, how short
is a piece of string? I've seen shorts at 8, 16 or 32 bit and now
completely hate the word short :)

Anyone reading your code is going to assume that LONG means long.
If it does, it's redundant; if it's not, it's misleading.
 
C

Christian Bau

Stephen said:
Is there a standard way to remove the warning that a C compiler might
produce from the statement:

if (a = b) {}

I don't want to do:

if ((a = b) != 0) {}

Because my "a = b" is actually contained in a macro that might be used
as a statement or as an expression within (for example) an "if"
statement.

If it makes any difference, here's exactly what I'm trying to do. In
order to get around a limitation of a particular C compiler that will
not allow p++ (or any other pointer arithmetic) to work correctly across
64KB boundaries, I have come up with a few macros, one of which is:

#define FARPTR_INC(p) p=(void far *)(((ULONG)(p))+sizeof(*(p)))

God, this is so broken, it is not funny anymore.

On the ancient compilers that I know where incrementing a pointer past a
64 KB boundary didn't work, this code would _definitely_ not work.

Hint: On an x86 in 16 bit mode, the difference between one legal segment
and the next one is not one, but eight.
 
K

Keith Thompson

Christian Bau said:
God, this is so broken, it is not funny anymore.

On the ancient compilers that I know where incrementing a pointer past a
64 KB boundary didn't work, this code would _definitely_ not work.

Hint: On an x86 in 16 bit mode, the difference between one legal segment
and the next one is not one, but eight.

The OP isn't using an x86.
 

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

Similar Threads


Members online

No members online now.

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top