459,212 Members | 1,377 Online
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,212 IT Pros & Developers. It's quick & easy.

# Confirm this is Standard code

 P: n/a 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. Nov 14 '05 #1
18 Replies

 P: n/a On 2 Apr 2005 14:09:21 -0800, "joshc" wrote in comp.lang.c: 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 ? 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. -- Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html comp.lang.c++ http://www.parashift.com/c++-faq-lite/ alt.comp.lang.learn.c-c++ http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html Nov 14 '05 #2

 P: n/a In article <11**********************@g14g2000cwa.googlegroups .com>, joshc wrote:/* 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. -- Would you buy a used bit from this man?? Nov 14 '05 #3

 P: n/a Jack Klein wrote: On 2 Apr 2005 14:09:21 -0800, "joshc" wrote in 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. 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. Yeah, pre-conditioned to ensure what you describe above(0 to -31). Thanks. Nov 14 '05 #4

 P: n/a Walter Roberson wrote: In article <11**********************@g14g2000cwa.googlegroups .com>, joshc wrote:/* 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. -- Would you buy a used bit from this man?? 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. Nov 14 '05 #5

 P: n/a On Sat, 02 Apr 2005 23:46:46 +0000, Walter Roberson wrote: In article <11**********************@g14g2000cwa.googlegroups .com>, joshc wrote:/* 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? 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 Nov 14 '05 #6

 P: n/a In article , Lawrence Kirby wrote: Would the cast not be processed before the unary minus?That seems to be the intent. Thanks for the detailed explanation, Lawrence if(val < 0) abs_val = (uint32)(-val); The problem here is that -val can result in undefined behaviour which iswhat 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; -- Walter Roberson is my name, And Usenet is my nation. Cyber space is my dwelling pace, And flames my destination. Nov 14 '05 #7

 P: n/a On 2 Apr 2005 15:50:44 -0800, "joshc" wrote in comp.lang.c: Jack Klein wrote: On 2 Apr 2005 14:09:21 -0800, "joshc" wrote in comp.lang.c: Why not just: abs_val = abs(val); 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. 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. 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. -- Jack Klein Home: http://JK-Technology.Com FAQs for comp.lang.c http://www.eskimo.com/~scs/C-faq/top.html comp.lang.c++ http://www.parashift.com/c++-faq-lite/ alt.comp.lang.learn.c-c++ http://www.contrib.andrew.cmu.edu/~a...FAQ-acllc.html Nov 14 '05 #8

 P: n/a Walter Roberson wrote: Lawrence Kirby wrote: if(val < 0) abs_val = (uint32)(-val); 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? ... Or find a (big-picture) algorithm that doesn't require the magnitude of a signed int in the first place. -- Peter Nov 14 '05 #9

 P: n/a Jack Klein wrote: On 2 Apr 2005 15:50:44 -0800, "joshc" wrote in comp.lang.c: Jack Klein wrote: On 2 Apr 2005 14:09:21 -0800, "joshc" wrote in comp.lang.c: Why not just: abs_val = abs(val); 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. 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 :). 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. 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. If you want the whole story I can tell you offline. Let me know. Nov 14 '05 #10

 P: n/a joshc wrote: Jack Klein wrote: .... snip ... 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. 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. -- "If you want to post a followup via groups.google.com, don't use the broken "Reply" link at the bottom of the article. Click on "show options" at the top of the article, then click on the "Reply" at the bottom of the article headers." - Keith Thompson Nov 14 '05 #11

 P: n/a On Sun, 03 Apr 2005 17:02:55 +0000, Walter Roberson wrote: In article , Lawrence Kirby wrote: Would the cast not be processed before the unary minus?That seems to be the intent. Thanks for the detailed explanation, Lawrence if(val < 0) abs_val = (uint32)(-val);The problem here is that -val can result in undefined behaviour which iswhat 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. 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 Nov 14 '05 #12

 P: n/a CBFalconer wrote: joshc wrote: Jack Klein wrote: ... snip ... 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. 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. Nov 14 '05 #13

 P: n/a Lawrence Kirby wrote: On Sun, 03 Apr 2005 17:02:55 +0000, Walter Roberson wrote: snip...The problem here is that -val can result in undefined behaviour which iswhat 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. 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, 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. Nov 14 '05 #14

 P: n/a Lawrence Kirby wrote: .... 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. -- "If you want to post a followup via groups.google.com, don't use the broken "Reply" link at the bottom of the article. Click on "show options" at the top of the article, then click on the "Reply" at the bottom of the article headers." - Keith Thompson Nov 14 '05 #15

 P: n/a Jack Klein wrote: What puzzles me is WHY you want to write code like this. On 2 Apr 2005 14:09:21 -0800, "joshc" wrote in comp.lang.c: /* 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 ? 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. 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. 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 Nov 14 '05 #16

 P: n/a CBFalconer wrote: Lawrence Kirby wrote: ... 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. 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. Nov 14 '05 #17

 P: n/a joshc wrote: CBFalconer wrote: Lawrence Kirby wrote: ... 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. 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. -- "If you want to post a followup via groups.google.com, don't use the broken "Reply" link at the bottom of the article. Click on "show options" at the top of the article, then click on the "Reply" at the bottom of the article headers." - Keith Thompson Nov 14 '05 #18

 P: n/a On 2 Apr 2005 14:09:21 -0800, joshc wrote: 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 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 Nov 14 '05 #19

### This discussion thread is closed

Replies have been disabled for this discussion.