Confirm this is Standard code

J

joshc

I've got two bits of code that I would like some more experienced folks
to check for conformance to the Standard. I've tried my best to read
the standard and search around and I think and hope this code contains
no cause for concern.

/* taking absolute value of signed integer */
int32 val;
uint32 abs_val;

val = -492;

if(val < 0)
abs_val = -(uint32)val;

I have done my reading of the standard on this and searching around and
it seems the above is fine by the standard. Just want to make sure
because my lint warns about "Expected signed type".


Also please look at the code below and tell me if there is anything to
worry about as far as being non-standard. Just a note, the absolute
value of shiftAmt has already been pre-conditioned and is guaranteed
not to overflow an int16 so don't warn me about that possibly
overflowing and resulting in U.B..

int32 foo(int16 x, int16 shiftAmt)
{
int32 ret;

...
/* code block dealing with x < 0, shiftAmt < 0 */
ret = -((int32)((-(uint32)x) << (-shiftAmt)));
}

Thanks.
 
J

Jack Klein

I've got two bits of code that I would like some more experienced folks
to check for conformance to the Standard. I've tried my best to read
the standard and search around and I think and hope this code contains
no cause for concern.

What puzzles me is WHY you want to write code like this.
/* taking absolute value of signed integer */
int32 val;
uint32 abs_val;

val = -492;

if(val < 0)
abs_val = -(uint32)val;

Why not just:

abs_val = abs(val);

....after including <stdlib.h>? Or just:

abs_val = val > 0 ? val : -val;

In any case, the result of the code is well-defined if val is negative
unless it happens to be the minimum possible value and has a magnitude
of on greater than the maximum positive value.
I have done my reading of the standard on this and searching around and
it seems the above is fine by the standard. Just want to make sure
because my lint warns about "Expected signed type".

Also please look at the code below and tell me if there is anything to
worry about as far as being non-standard. Just a note, the absolute
value of shiftAmt has already been pre-conditioned and is guaranteed
not to overflow an int16 so don't warn me about that possibly
overflowing and resulting in U.B..

Pre-conditioned to be what? Since you are casting to a 32 bit type
before the shift, and returning a 32 bit value, what might overflow a
16 bit type doesn't make any difference.
int32 foo(int16 x, int16 shiftAmt)
{
int32 ret;

...
/* code block dealing with x < 0, shiftAmt < 0 */
ret = -((int32)((-(uint32)x) << (-shiftAmt)));

If shiftAmt was between 0 and -31 inclusive, this has well defined
results but looks quite bizarre. If shiftAmt is positive or less than
-32, it has undefined results.
}

Thanks.

Can you describe in words exactly what it is you are trying to do with
this code? Whatever it is, I am pretty sure that there is a much less
convoluted way to write it.
 
W

Walter Roberson

/* taking absolute value of signed integer */
int32 val;
uint32 abs_val;

val = -492;

if(val < 0)
abs_val = -(uint32)val;

Would the cast not be processed before the unary minus? I could be wrong
but that code -looks- to me to be doing the following:

1) take a negative number and make it into an unsigned value
(I would have to re-read the standard to see what it says
about exactly what would happen)
2) does a unary minus on the unsigned value
(I would have to re-read the standard to see what unary minus
means when applied to an unsigned value)
3) sees that the value is to be assigned to an unsigned value, so
potentially converts the value again.

It would make more sense to me if the code were

if(val < 0)
abs_val = (uint32)(-val);

at which point the cast would merely be redundant, with no
possibility of a triple conversion.
 
J

joshc

Jack said:
comp.lang.c:


Why not just:

abs_val = abs(val);

This is code for an embedded system, i.e a freestanding implementation.
Pre-conditioned to be what? Since you are casting to a 32 bit type
before the shift, and returning a 32 bit value, what might overflow a
16 bit type doesn't make any difference.


If shiftAmt was between 0 and -31 inclusive, this has well defined
results but looks quite bizarre. If shiftAmt is positive or less than
-32, it has undefined results.

Yeah, pre-conditioned to ensure what you describe above(0 to -31).

Thanks.
 
J

joshc

Walter said:
Would the cast not be processed before the unary minus? I could be wrong
but that code -looks- to me to be doing the following:

1) take a negative number and make it into an unsigned value
(I would have to re-read the standard to see what it says
about exactly what would happen)
2) does a unary minus on the unsigned value
(I would have to re-read the standard to see what unary minus
means when applied to an unsigned value)
3) sees that the value is to be assigned to an unsigned value, so
potentially converts the value again.

It would make more sense to me if the code were

if(val < 0)
abs_val = (uint32)(-val);

at which point the cast would merely be redundant, with no
possibility of a triple conversion.


Basically the reason I do this is so that I don't get signed integer
overflow because that results in undefined behavior. On the other hand,
dealing with unsigned integers there is no overflow and all arithmetic
operations are performed mod UINT_MAX+1 or whatever the relevant limit
is.
 
W

Walter Roberson

That seems to be the intent.

Thanks for the detailed explanation, Lawrence
The problem here is that -val can result in undefined behaviour which is
what the code is trying to avoid.

If I understand correctly, the undefined behaviour would be at
the boundary condition, where val is the most negative value.
Perhaps special case that particular value?

if (val == INT32_MIN) abs_val = 0;
else if (val < 0) abs_val = -val;
else abs_val = val;
 
L

Lawrence Kirby

Would the cast not be processed before the unary minus?

That seems to be the intent.
I could be wrong
but that code -looks- to me to be doing the following:

1) take a negative number and make it into an unsigned value
(I would have to re-read the standard to see what it says
about exactly what would happen)

It says the result is the value you get by adding one more than the
largest value representable in the unsigned type. Call that largest value
UINT32_MAX then the result is aritmetically val + UINT32_MAX+1.
-(uint32)val is then -val-(UINT32_MAX+1). To bring that back into
a representable value when it is negative we must add UINT32_MAX+1 again
giving -val-(UINT32_MAX+1)+(UINT32_MAX+1) i.e. -val. This gives us the
result we want as an unsigned value. The only situation where this "fails"
is when the absolute value of val is not representable as a uint32, in
that case the result turns out to be zero. That's unlikely because
unsigned types usually have a larger positive range then their
corresponding signed types.
2) does a unary minus on the unsigned value
(I would have to re-read the standard to see what unary minus
means when applied to an unsigned value)
3) sees that the value is to be assigned to an unsigned value, so
potentially converts the value again.

It would make more sense to me if the code were

if(val < 0)
abs_val = (uint32)(-val);

at which point the cast would merely be redundant, with no
possibility of a triple conversion.

The problem here is that -val can result in undefined behaviour which is
what the code is trying to avoid.

Lawrence
 
J

Jack Klein

This is code for an embedded system, i.e a freestanding implementation.

I understand all about embedded systems, that what I've been doing for
25 years.
Yeah, pre-conditioned to ensure what you describe above(0 to -31).

Thanks.

I still don't understand why you are writing code this way. Why have
you written the code in such an unusual and complex manner?

Again, post an explanation of what it is you are trying to do, what
the values are and what you need to do to them. There must be a
simpler way to write code to do what you need.
 
P

Peter Nilsson

Walter said:
If I understand correctly, the undefined behaviour would be at
the boundary condition, where val is the most negative value.
Perhaps special case that particular value? ...

Or find a (big-picture) algorithm that doesn't require the
magnitude of a signed int in the first place.
 
J

joshc

Jack said:
implementation.

I understand all about embedded systems, that what I've been doing for
25 years.

Heh, sorry, I didn't mean it to sound the way you took it. I don't have
25 years experience and that's why I am asking these questions :).
I still don't understand why you are writing code this way. Why have
you written the code in such an unusual and complex manner?

Again, post an explanation of what it is you are trying to do, what
the values are and what you need to do to them. There must be a
simpler way to write code to do what you need.

If you want the whole story I can tell you offline. Let me know.
 
C

CBFalconer

joshc said:
Jack Klein wrote:
.... snip ...

If you want the whole story I can tell you offline. Let me know.

No, you are the one who wants help. Jack is telling you to explain
what you are trying to do, and you may get some help. Simply
squalling that you want to square the circle won't go far. You may
get told that your objectives are off-topic, but that doesn't seem
likely in this case.
 
L

Lawrence Kirby

Thanks for the detailed explanation, Lawrence



If I understand correctly, the undefined behaviour would be at
the boundary condition, where val is the most negative value.

That is the problem case, specifically when INT32_MIN has a greater
magnitude than INT32_MAX.
Perhaps special case that particular value?

if (val == INT32_MIN) abs_val = 0;

Better would be if (val < -INT32_MAX) because C doesn't require minimum
values to have a larger magnitude than maximum ones.
else if (val < 0) abs_val = -val;
else abs_val = val;

This is more complex and probably less efficient which might be relevant
to some people. abs_val = (uint32)(-val); produces the correct value
(rather than 0) for INT32_MIN if uint32 can represent it. Once you see
what it is doing this is a simple and clean solution to the problem. It
can produce an incorrect result (0) in rare to non-existant
circumstances when the correct result is not representable, but it
doesn't have any undefined behaviour.

Lawrence
 
J

joshc

CBFalconer said:
No, you are the one who wants help. Jack is telling you to explain
what you are trying to do, and you may get some help. Simply
squalling that you want to square the circle won't go far. You may
get told that your objectives are off-topic, but that doesn't seem
likely in this case.

My question has already been answered so that indicates that the
information I gave was sufficient for people to address the question. I
just wanted someone to confirm that was standard C and wasn't really
looking for advice on how to "better" write my algorithm.

Anyhow, since people seem interested, what that code is part of is a
fixed-point subtraction routine. I need to subtract an unsigned
fixed-point number from a signed fixed-pt number. In particular, in
that "odd" looking code, int16 x is the signed fixed-point number which
I am trying to scale to match the radix point position of the other
operand. Please don't ask me why signed and unsigned types are involved
in the subtraction, that is beyond my control and I also think it's
stupid.

Thanks for your help.
 
J

joshc

Lawrence said:
That is the problem case, specifically when INT32_MIN has a greater
magnitude than INT32_MAX.


Better would be if (val < -INT32_MAX) because C doesn't require minimum
values to have a larger magnitude than maximum ones.


This is more complex and probably less efficient which might be relevant
to some people. abs_val = (uint32)(-val); produces the correct value
(rather than 0) for INT32_MIN if uint32 can represent it. Once you see
what it is doing this is a simple and clean solution to the problem. It
can produce an incorrect result (0) in rare to non-existant
circumstances when the correct result is not representable, but it
doesn't have any undefined behaviour.

Lawrence, I'm a little confused by what seems to me to be a disparity
between what you said a few posts above and what you say in this post.
In this post you say that abs_val = (uint32)(-val) doesn't have any
undefined behavior. I thought you confirmed a few posts above that it
_does_ have undefined behavior if val=INT32_MIN and abs(INT32_MIN) >
INT32_MAX.

I may be misunderstanding your post so please clarify.

Thanks.
 
C

CBFalconer

Lawrence said:
.... snip ...

This is more complex and probably less efficient which might be
relevant to some people. abs_val = (uint32)(-val); produces the
correct value (rather than 0) for INT32_MIN if uint32 can
represent it. Once you see what it is doing this is a simple and
clean solution to the problem. It can produce an incorrect result
(0) in rare to non-existant circumstances when the correct result
is not representable, but it doesn't have any undefined behaviour.

Except that "(uint32)(-val)" for val == INT_MIN should produce the
value 0 for the normal value of UINT_MAX.
 
M

Mark Piffer

Jack said:
What puzzles me is WHY you want to write code like this.



Why not just:

abs_val = abs(val);

...after including <stdlib.h>? Or just:

abs_val = val > 0 ? val : -val;

In any case, the result of the code is well-defined if val is negative
unless it happens to be the minimum possible value and has a magnitude
of on greater than the maximum positive value.

I suppose he tried to avoid exactly your "unless" case.

Pre-conditioned to be what? Since you are casting to a 32 bit type
before the shift, and returning a 32 bit value, what might overflow a
16 bit type doesn't make any difference.


If shiftAmt was between 0 and -31 inclusive, this has well defined
results but looks quite bizarre. If shiftAmt is positive or less than
-32, it has undefined results.

Is that they are well defined in the sense that they are implementation
defined? Doesn't every argument pair that creates something > INT32_MAX
invoke implementation defined behaviour at the (int32) cast (e.g.
foo(-2,-31))?
BTW, how are integer promotions executed on extended integer types? Are
they left untouched even when an int is wider than a int32_t?

Mark
 
J

joshc

CBFalconer said:
Except that "(uint32)(-val)" for val == INT_MIN should produce the
value 0 for the normal value of UINT_MAX.

How??? The cast is happening after the negation so I don't see how this
isn't undefined behavior in the case I mentioned where you have
|INT_MIN| > INT_MAX.
 
C

CBFalconer

joshc said:
How??? The cast is happening after the negation so I don't see how
this isn't undefined behavior in the case I mentioned where you
have |INT_MIN| > INT_MAX.

You're right. I'm wrong.
 
V

Villy Kruse

I've got two bits of code that I would like some more experienced folks
to check for conformance to the Standard. I've tried my best to read
the standard and search around and I think and hope this code contains
no cause for concern.

/* taking absolute value of signed integer */
int32 val;
uint32 abs_val;

I would have thought that int32 and uint32 were not standards conform
but int32_t and uint32_t as defined in <stdint.h> are on platform where
such types are supported.

int32 and uint32 could be user defined types in part of the code not
listed, though.

Villy
 

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
474,161
Messages
2,570,892
Members
47,428
Latest member
RosalieQui

Latest Threads

Top