"Phil Hobbs" <pcdhSpamMeSenseless@electrooptical.net> wrote in message news:1vmdnTElaNo_lUrLnZ2dnUU7-RHNnZ2d@supernews.com...> On 03/01/2016 04:12 PM, Tim Wescott wrote: >> On Tue, 01 Mar 2016 21:02:46 +0000, tim... wrote: >> >>> Today, I discovered that if you use: >>> >>> const unsigned int xxx = value; (which in this case happens to be >>> = 0) >>> >>> and then in the code try and compare it with a signed int yyy >>> >>> the compiler ignores your signed int and does an unsigned compare. >>> >>> Up until now this hadn't been a problem as I've (quite by chance) >>> always looked for equality with the const. >>> >>> But today I counted yyy down to -1 wishing to stop when yyy < xxx >>> but the sodding compiler decided that I now had a very large >>> positive number and refused to break from my loop. >>> >>> Took me flipping ages to work out what was wrong :-( >>> >>> The compiler does give me a warning - that I am comparing a signed >>> with an unsigned but as I was sure that the unsigned int was the >>> zero value const I didn't give it a second thought. >>> >>> But I did get rid of it by using a c-style cast to make the >>> unsigned int a signed one when comparing, and that suppressed the >>> warning, but it still didn't work. - not until I redefined my >>> const as signed! >>> >>> I'm not hugely experienced with C++ [1], is it meant to work like >>> this or do I have a broken compiler? >>> >>> We're using GCC >>> >>> TIA >>> >>> Tim >>> >>> [1] nor are any of my co-workers, finding good ones who will work >>> for the pittance that embedded work now pays in my neck of the >>> woods is tres difficult :-) >> >> 1: Yes, it's supposed to work like that. Google "automatic type >> conversions". > > Yup, downcounting loops with unsigned loop counters is a classic bug. > The OP will remember next time. ;)The counter IS (was) signed, it is the const value being compared against that is not> Signed ints don't have the problem, obviously, and this is one reason > it's a bad idea to reuse loop counter variables, unless you're writing > for an 8-bit MCU.it's the const that being reused (sort of) here, everywhere else they need to be unsigned because we need the range :-( I now have an inconsistency in my set of definitions for this class tim
C++ problem
Started by ●March 1, 2016
Reply by ●March 2, 20162016-03-02
Reply by ●March 2, 20162016-03-02
"Tim Wescott" <tim@seemywebsite.com> wrote in message news:OaidnQaVUvYumEvLnZ2dnUU7-UmdnZ2d@giganews.com...> On Tue, 01 Mar 2016 21:02:46 +0000, tim... wrote: > >> Today, I discovered that if you use: >> >> const unsigned int xxx = value; (which in this case happens to be = 0) >> >> and then in the code try and compare it with a signed int yyy >> >> the compiler ignores your signed int and does an unsigned compare. >> >> Up until now this hadn't been a problem as I've (quite by chance) always >> looked for equality with the const. >> >> But today I counted yyy down to -1 wishing to stop when yyy < xxx but >> the sodding compiler decided that I now had a very large positive number >> and refused to break from my loop. >> >> Took me flipping ages to work out what was wrong :-( >> >> The compiler does give me a warning - that I am comparing a signed with >> an unsigned but as I was sure that the unsigned int was the zero value >> const I didn't give it a second thought. >> >> But I did get rid of it by using a c-style cast to make the unsigned int >> a signed one when comparing, and that suppressed the warning, but it >> still didn't work. - not until I redefined my const as signed! >> >> I'm not hugely experienced with C++ [1], is it meant to work like this >> or do I have a broken compiler? >> >> We're using GCC >> >> TIA >> >> Tim >> >> [1] nor are any of my co-workers, finding good ones who will work for >> the pittance that embedded work now pays in my neck of the woods is tres >> difficult :-) > > 1: Yes, it's supposed to work like that. Google "automatic type > conversions". > > 2: I'm pretty sure that C is supposed to work like that, too. If it > isn't, then the behavior is implementation defined -- meaning that it > won't be predictable at all.If I was working in C I wouldn't have the a typed const variable at all I'd be using an untyped define> 3: "by using a c-style cast to make the unsigned int a signed one when > comparing, and that suppressed the warning, but it still didn't work. - > not until I redefined my const as signed!" > > What? 'splain, please. I thought the const was the only unsigned. > > You should use a C++ - style cast:probably :-) an awful lot of C++ work is done without it, IME tim
Reply by ●March 2, 20162016-03-02
"rickman" <gnuarm@gmail.com> wrote in message news:nb59m8$9qc$1@dont-email.me...> On 3/1/2016 5:20 PM, Hans-Bernhard Br�ker wrote: >> Am 01.03.2016 um 22:02 schrieb tim...: >>> The compiler does give me a warning - that I am comparing a signed with >>> an unsigned but as I was sure that the unsigned int was the zero value >>> const I didn't give it a second thought. >> >> That reasoning was just wrong. The thing you were sure about is >> correct. It doesn't support the conclusion you drew, though. >> >>> But I did get rid of it by using a c-style cast to make the unsigned >>> int a signed one when comparing, and that suppressed the warning, but >>> it still didn't work. - not until I redefined my const as signed! >> >> That attempt most probably failed in some other, unrelated way. Which >> way it was can only be found out if you show an actual, essentially >> complete (as in: compilable) example case. > > That's easy. He said he was counting down to -1 which won't work if the > value is cast to an unsigned.It wasn't cast to an unsigned, it was compared to an unsigned (the cast was an attempt to make the unsigned signed - but that didn't work either) tim
Reply by ●March 2, 20162016-03-02
On Wed, 2 Mar 2016 17:55:20 -0000, "tim..." <tims_new_home@yahoo.com> wrote:> >"Phil Hobbs" <pcdhSpamMeSenseless@electrooptical.net> wrote in message >news:1vmdnTElaNo_lUrLnZ2dnUU7-RHNnZ2d@supernews.com... >> On 03/01/2016 04:12 PM, Tim Wescott wrote: >>> On Tue, 01 Mar 2016 21:02:46 +0000, tim... wrote: >>> >>>> Today, I discovered that if you use: >>>> >>>> const unsigned int xxx = value; (which in this case happens to be >>>> = 0) >>>> >>>> and then in the code try and compare it with a signed int yyy >>>> >>>> the compiler ignores your signed int and does an unsigned compare. >>>> >>>> Up until now this hadn't been a problem as I've (quite by chance) >>>> always looked for equality with the const. >>>> >>>> But today I counted yyy down to -1 wishing to stop when yyy < xxx >>>> but the sodding compiler decided that I now had a very large >>>> positive number and refused to break from my loop. >>>> >>>> Took me flipping ages to work out what was wrong :-( >>>> >>>> The compiler does give me a warning - that I am comparing a signed >>>> with an unsigned but as I was sure that the unsigned int was the >>>> zero value const I didn't give it a second thought. >>>> >>>> But I did get rid of it by using a c-style cast to make the >>>> unsigned int a signed one when comparing, and that suppressed the >>>> warning, but it still didn't work. - not until I redefined my >>>> const as signed! >>>> >>>> I'm not hugely experienced with C++ [1], is it meant to work like >>>> this or do I have a broken compiler? >>>> >>>> We're using GCC >>>> >>>> TIA >>>> >>>> Tim >>>> >>>> [1] nor are any of my co-workers, finding good ones who will work >>>> for the pittance that embedded work now pays in my neck of the >>>> woods is tres difficult :-) >>> >>> 1: Yes, it's supposed to work like that. Google "automatic type >>> conversions". >> >> Yup, downcounting loops with unsigned loop counters is a classic bug. >> The OP will remember next time. ;) > >The counter IS (was) signed, it is the const value being compared against >that is notEither way - the usual promotions cause to conversion to unsigned if either argument is unsigned.
Reply by ●March 2, 20162016-03-02
On 02/03/16 16:37, Phil Hobbs wrote:> On 03/01/2016 04:12 PM, Tim Wescott wrote: >> On Tue, 01 Mar 2016 21:02:46 +0000, tim... wrote:>> 1: Yes, it's supposed to work like that. Google "automatic type >> conversions". > > Yup, downcounting loops with unsigned loop counters is a classic bug. > The OP will remember next time. ;)I don't know whether it counts as a "classic" bug, but if your code relies on an unsigned variable going below zero, it has a bug. However, I think the OP's counter variable was signed.> > Signed ints don't have the problem, obviously, and this is one reason > it's a bad idea to reuse loop counter variables, unless you're writing > for an 8-bit MCU. >That is two (or is it three?) complete non-sequiturs. Signed ints can go below zero - that's why they are called "signed". Reusing loop counter variables is perfectly fine - the only "bad idea" about reusing loop counters is that it is usually considered good modern programming practice to keep the scope tight, and declare them inside your for-loop. Certainly the use or reuse of loop counter variables is totally independent of the choice of signed or unsigned types. And the issues or non-issues of the signedness of your types, and the use or reuse of your loop variables, are both totally independent of the size of your MCU. The only possible vague connection is that if you have a truly crappy compiler, which is unlikely for a 32-bit processor but may be the case for some 8-bit devices, then your code might be more efficient if you reuse your loop variables. And some very brain-dead processors (like the COP8) are more efficient at dealing with unsigned variables than signed ones.>> >> 2: I'm pretty sure that C is supposed to work like that, too. If it >> isn't, then the behavior is implementation defined -- meaning that >> it won't be predictable at all. > > Since essentially all computers still crunching use twos-complement binary > for signed ints, that behaviour is very nearly guaranteed. IIRC you can > turn on integer overflow traps so that it behaves like a divide-by-zero, > but a whole lot of software relies on this behaviour. >This has nothing to do with using two's complement for signed data - it concerns the standard C integer promotion rules, which are independent of the representation of signed integers. And in C, the two's complement nature of signed integers is only relevant when you are re-interpreting the raw data, such as via a union - arithmetic on signed data is never guaranteed to act in a two's complement fashion (overflows are undefined, not implementation defined). So any code that relies on overflow behaviour or wrapping behaviour of signed ints is broken code. There is, as yet, no sign that the OP wrote such code - we won't know for sure unless he shows it to us. One some platforms, with some compilers, you can enable trapping on signed integer overflow. It is not supported on most embedded platforms, and works poorly even on the best supported platforms (since compiler optimisations can make generated code that appears significantly different from the source code). Don't try to use it.>> >> 3: "by using a c-style cast to make the unsigned int a signed one >> when comparing, and that suppressed the warning, but it still didn't >> work. - not until I redefined my const as signed!" >> >> What? 'splain, please. I thought the const was the only unsigned. >> >> You should use a C++ - style cast: >> >> if (static_cast<int>(xxx) >= yyy) { yadda yadda } >> >> 4: Use -Wall. Then, since "all" does not, somehow, mean "all" to the >> crew at GCC, use -Wextra, too. > > Yup. A copy of PC-Lint is helpful too (assuming they've kept it up to > date--my copy doesn't understand anything past C++08.) >I have found little of interest in PC-Lint - there are few warnings that would be triggered by anything I am likely to write that are not also found by gcc's rather extensive warnings. However, people write different sorts of code - others may find it useful, as might people who don't have good warnings from their compilers (like reasonably modern gcc or clang).
Reply by ●March 2, 20162016-03-02
On 02/03/16 18:58, tim... wrote:> > "Tim Wescott" <tim@seemywebsite.com> wrote in message > news:OaidnQaVUvYumEvLnZ2dnUU7-UmdnZ2d@giganews.com... >> On Tue, 01 Mar 2016 21:02:46 +0000, tim... wrote: >> >>> Today, I discovered that if you use: >>> >>> const unsigned int xxx = value; (which in this case happens to be = 0) >>> >>> and then in the code try and compare it with a signed int yyy >>> >>> the compiler ignores your signed int and does an unsigned compare. >>> >>> Up until now this hadn't been a problem as I've (quite by chance) always >>> looked for equality with the const. >>> >>> But today I counted yyy down to -1 wishing to stop when yyy < xxx but >>> the sodding compiler decided that I now had a very large positive number >>> and refused to break from my loop. >>> >>> Took me flipping ages to work out what was wrong :-( >>> >>> The compiler does give me a warning - that I am comparing a signed with >>> an unsigned but as I was sure that the unsigned int was the zero value >>> const I didn't give it a second thought. >>> >>> But I did get rid of it by using a c-style cast to make the unsigned int >>> a signed one when comparing, and that suppressed the warning, but it >>> still didn't work. - not until I redefined my const as signed! >>> >>> I'm not hugely experienced with C++ [1], is it meant to work like this >>> or do I have a broken compiler? >>> >>> We're using GCC >>> >>> TIA >>> >>> Tim >>> >>> [1] nor are any of my co-workers, finding good ones who will work for >>> the pittance that embedded work now pays in my neck of the woods is tres >>> difficult :-) >> >> 1: Yes, it's supposed to work like that. Google "automatic type >> conversions". >> >> 2: I'm pretty sure that C is supposed to work like that, too. If it >> isn't, then the behavior is implementation defined -- meaning that it >> won't be predictable at all. > > If I was working in C I wouldn't have the a typed const variable at all > I'd be using an untyped defineWhy? C supports typed consts much like C++. There are a few differences (other than the obvious one that C++ has a more complete type system). In C++, something like "const int x = 10;" is static by default - in C, you need to explicitly write "static const int x = 10;". And in C++, x would be a constant expression that you can use for things like array sizes - in C, it is not a constant expression. But other than that, for the sort of uses you are discussing, in C you could/should also use a typed const. And the rules for integer promotion and arithmetic conversions are identical in C and C++.> >> 3: "by using a c-style cast to make the unsigned int a signed one when >> comparing, and that suppressed the warning, but it still didn't work. - >> not until I redefined my const as signed!" >> >> What? 'splain, please. I thought the const was the only unsigned. >> >> You should use a C++ - style cast: > > probably :-) > > an awful lot of C++ work is done without it, IME > > tim > > >
Reply by ●March 2, 20162016-03-02
Am 02.03.2016 um 00:50 schrieb rickman:> On 3/1/2016 5:20 PM, Hans-Bernhard Br�ker wrote: >> Am 01.03.2016 um 22:02 schrieb tim...:>>> But I did get rid of it by using a c-style cast to make the unsigned >>> int a signed one when comparing, and that suppressed the warning, but >>> it still didn't work. - not until I redefined my const as signed!>> That attempt most probably failed in some other, unrelated way. Which >> way it was can only be found out if you show an actual, essentially >> complete (as in: compilable) example case. > > That's easy. He said he was counting down to -1 which won't work if the > value is cast to an unsigned.No, it's not that easy, because per his actual statement (see above) he did _not_ cast the signed -1 to unsigned in this try; he said he cast the const unsigned 0 to signed, instead. That should have worked.
Reply by ●March 2, 20162016-03-02
On 02/03/16 15:59, Dimiter_Popoff wrote:> On 02.3.2016 г. 16:50, David Brown wrote: >> On 02/03/16 15:08, Dimiter_Popoff wrote: >>> On 02.3.2016 г. 15:17, raimond.dragomir@gmail.com wrote: >>>> miercuri, 2 martie 2016, 14:45:34 UTC+2, David Brown a scris: >>>>> On 02/03/16 11:50, raimond.dragomir@gmail.com wrote: >>>>>>> int32_t a1 = (int32_t) a; >>>>>>> int32_t b1 = (int32_t) b; >>>>>>> int32_t res1 = a1 * b1; >>>>>>> >>>>>>> If this is called with a and b equal to 0xffff, the 32-bit signed >>>>>>> multiplication will overflow - it is undefined behaviour. >>>>>>> >>>>>> Since you want only 32bit of the result, this is correct. You get >>>>>> incorrect >>>>>> results only if you use full multiplication (64bit result) with >>>>>> different >>>>>> unsigned/signed operation/result. >>>>> >>>>> No, it is not correct - it is undefined behaviour. As signed 32-bit >>>>> ints, 0xffff * 0xffff would be an overflow, and therefore undefined >>>>> behaviour. Operations like that are not defined as nice two's >>>>> complement arithmetic in C (even though in practice, that is what the >>>>> compiler would probably generate). >>>>> >>>>>> >>>>>> When the result of a multiplication has the same size as the >>>>>> operands, the >>>>>> result is correct regardless signed/unsigned of any operands, >>>>>> including the >>>>>> result. This may be counter-intuitive unless you know what you are >>>>>> doing. >>>>>> You must remember that a multiplication always gives a double >>>>>> product, so >>>>>> taking only the low part gives you ... the low part. >>>>> >>>>> It has nothing to do with that (I understand how multiplication >>>>> works in >>>>> this context, though I appreciate that not everyone does). The >>>>> point to >>>>> be aware of here is that operations on unsigned types smaller than >>>>> "int" >>>>> are promoted to /signed/ int before the operation is carried out. >>>>> That >>>>> can mean you get unexpected undefined behaviour due to /signed/ >>>>> overflows, even though /unsigned/ overflow is fully defined in C (and >>>>> C++). >>>>> >>>>> The point is subtle, and it is unlikely to be an issue in >>>>> practice. But >>>>> I think it is worth mentioning these details. >>>> >>>> Sorry, maybe I don't understand your point. I basically said that >>>> taking the >>>> low part gives correct result. In the very example given, 0xffff >>>> (16bit initially) >>>> * 0xffff (16bit) gives the 0x0001 result (16bit). What 16bit result >>>> would >>>> you expect? >>>> This result is correct in both cases (a 16bit operation (if available) >>>> and a converted operation with signed 32bit integers). >>>> >>>> Can you give an example where the conversion of an unsigned to the >>>> bigger >>>> signed type and then the multiplied result of the signed numbers >>>> truncated >>>> back is wrong? >>>> >>>> >>> >>> I suppose he means that you do get the correct result by ignoring the >>> overflow, which after all is not the correct result. >>> >>> $ffff unsigned expands to 32 bit $0000ffff signed, $ffff signed >>> expands to $ffffffff signed. The signed product of these is $ffff0001, >>> which does not fit in 16 bits, it takes 17 bits at least. >>> Hardly a huge issue if one knows what he is doing, >>> but if you rely on a compiler to know these things for you it can't >>> be just dismissed. >>> >> >> No, the issue is that the signed product 0xffffffff does not fit in a >> signed 32-bit integer - and that is undefined behaviour. This >> intermediary value exists logically before the conversion to 16-bit >> unsigned by modulo arithmetic. >> >> > > David, the product is not $ffffffff - how did you arrive at that? >I used a little-known trick - the typo! The issue is that the signed product 0xffff0001 does not fit in a signed 32-bit integer, causing undefined behaviour. Sorry for the confusion.
Reply by ●March 2, 20162016-03-02
On 02/03/16 19:03, tim... wrote:> > "rickman" <gnuarm@gmail.com> wrote in message > news:nb59m8$9qc$1@dont-email.me... >> On 3/1/2016 5:20 PM, Hans-Bernhard Br�ker wrote: >>> Am 01.03.2016 um 22:02 schrieb tim...: >>>> The compiler does give me a warning - that I am comparing a signed with >>>> an unsigned but as I was sure that the unsigned int was the zero value >>>> const I didn't give it a second thought. >>> >>> That reasoning was just wrong. The thing you were sure about is >>> correct. It doesn't support the conclusion you drew, though. >>> >>>> But I did get rid of it by using a c-style cast to make the unsigned >>>> int a signed one when comparing, and that suppressed the warning, but >>>> it still didn't work. - not until I redefined my const as signed! >>> >>> That attempt most probably failed in some other, unrelated way. Which >>> way it was can only be found out if you show an actual, essentially >>> complete (as in: compilable) example case. >> >> That's easy. He said he was counting down to -1 which won't work if >> the value is cast to an unsigned. > > It wasn't cast to an unsigned, it was compared to an unsigned (the cast > was an attempt to make the unsigned signed - but that didn't work either) > > tim >Again, if you really want help, you need to post the relevant code (preferably a small snippet showing the issue, and preferably something directly compilable), along with a few details such as compiler version, target, and relevant compiler flags if you think the compiler is doing something odd.
Reply by ●March 2, 20162016-03-02
On 02.3.2016 г. 23:19, David Brown wrote:> On 02/03/16 15:59, Dimiter_Popoff wrote: >> On 02.3.2016 г. 16:50, David Brown wrote: >>> On 02/03/16 15:08, Dimiter_Popoff wrote: >>>> On 02.3.2016 г. 15:17, raimond.dragomir@gmail.com wrote: >>>>> miercuri, 2 martie 2016, 14:45:34 UTC+2, David Brown a scris: >>>>>> On 02/03/16 11:50, raimond.dragomir@gmail.com wrote: >>>>>>>> int32_t a1 = (int32_t) a; >>>>>>>> int32_t b1 = (int32_t) b; >>>>>>>> int32_t res1 = a1 * b1; >>>>>>>> >>>>>>>> If this is called with a and b equal to 0xffff, the 32-bit signed >>>>>>>> multiplication will overflow - it is undefined behaviour. >>>>>>>> >>>>>>> Since you want only 32bit of the result, this is correct. You get >>>>>>> incorrect >>>>>>> results only if you use full multiplication (64bit result) with >>>>>>> different >>>>>>> unsigned/signed operation/result. >>>>>> >>>>>> No, it is not correct - it is undefined behaviour. As signed 32-bit >>>>>> ints, 0xffff * 0xffff would be an overflow, and therefore undefined >>>>>> behaviour. Operations like that are not defined as nice two's >>>>>> complement arithmetic in C (even though in practice, that is what the >>>>>> compiler would probably generate). >>>>>> >>>>>>> >>>>>>> When the result of a multiplication has the same size as the >>>>>>> operands, the >>>>>>> result is correct regardless signed/unsigned of any operands, >>>>>>> including the >>>>>>> result. This may be counter-intuitive unless you know what you are >>>>>>> doing. >>>>>>> You must remember that a multiplication always gives a double >>>>>>> product, so >>>>>>> taking only the low part gives you ... the low part. >>>>>> >>>>>> It has nothing to do with that (I understand how multiplication >>>>>> works in >>>>>> this context, though I appreciate that not everyone does). The >>>>>> point to >>>>>> be aware of here is that operations on unsigned types smaller than >>>>>> "int" >>>>>> are promoted to /signed/ int before the operation is carried out. >>>>>> That >>>>>> can mean you get unexpected undefined behaviour due to /signed/ >>>>>> overflows, even though /unsigned/ overflow is fully defined in C (and >>>>>> C++). >>>>>> >>>>>> The point is subtle, and it is unlikely to be an issue in >>>>>> practice. But >>>>>> I think it is worth mentioning these details. >>>>> >>>>> Sorry, maybe I don't understand your point. I basically said that >>>>> taking the >>>>> low part gives correct result. In the very example given, 0xffff >>>>> (16bit initially) >>>>> * 0xffff (16bit) gives the 0x0001 result (16bit). What 16bit result >>>>> would >>>>> you expect? >>>>> This result is correct in both cases (a 16bit operation (if available) >>>>> and a converted operation with signed 32bit integers). >>>>> >>>>> Can you give an example where the conversion of an unsigned to the >>>>> bigger >>>>> signed type and then the multiplied result of the signed numbers >>>>> truncated >>>>> back is wrong? >>>>> >>>>> >>>> >>>> I suppose he means that you do get the correct result by ignoring the >>>> overflow, which after all is not the correct result. >>>> >>>> $ffff unsigned expands to 32 bit $0000ffff signed, $ffff signed >>>> expands to $ffffffff signed. The signed product of these is $ffff0001, >>>> which does not fit in 16 bits, it takes 17 bits at least. >>>> Hardly a huge issue if one knows what he is doing, >>>> but if you rely on a compiler to know these things for you it can't >>>> be just dismissed. >>>> >>> >>> No, the issue is that the signed product 0xffffffff does not fit in a >>> signed 32-bit integer - and that is undefined behaviour. This >>> intermediary value exists logically before the conversion to 16-bit >>> unsigned by modulo arithmetic. >>> >>> >> >> David, the product is not $ffffffff - how did you arrive at that? >> > > I used a little-known trick - the typo! The issue is that the signed > product 0xffff0001 does not fit in a signed 32-bit integer, causing > undefined behaviour. > > Sorry for the confusion. > >Uhm, so the "No" must also have been a typo ;). BTW the $ffff0001 does fit in a signed 32 bit integer, it does not fit in 16 bits (fits in 17 bits). Dimiter







