C++ problem

If I was working in C I wouldn't have the a typed const variable at all I'd be using an untyped define

probably :-)

an awful lot of C++ work is done without it, IME

tim

Reply to
tim...
Loading thread data ...

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 to
tim...

Either way - the usual promotions cause to conversion to unsigned if either argument is unsigned.

Reply to
Robert Wessel

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.

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.

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.

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 to
David Brown

Why? 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++.

Reply to
David Brown

Am 02.03.2016 um 00:50 schrieb rickman:

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 to
Hans-Bernhard Bröker

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 to
David Brown

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 to
David Brown

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

Reply to
Dimiter_Popoff

No, the "no" was not a typo - and no, 0xffff0001 does not fit in a signed 32-bit integer. The range for a 32-bit signed integer is

-0x80000000 to +0x7fffffff. 0xffff0001 is outside of that range, and cannot be represented.

Reply to
David Brown

I think it's 0xfffe0001, but yeah, that is 4294901761 decimal, which is not representable as a signed int32.

Reply to
Paul Rubin

Yes, I have it backwards. So why didn't that work?

--

Rick
Reply to
rickman

LOL, David. So you have yet to learn that the signed product of (-1)*(65535) (signed $ffff 16 bit * unsigned $ffff 16 bit) is -65535, representable in 32 bits as $ffff0001, does fit in a minimum of 17 bits and of course does fit in 32 bits.

How long did you say you had been working as a programmer? :D

Dimiter

Reply to
Dimiter_Popoff

I'm sure we could easily figure it out, but only if he shows us the code.

Reply to
Philip Lantz

I don't believe in utilizing such behavior. The language has typing for a reason and ignoring it can get you into trouble as happened here.

Why would anyone need PC-Lint? The compiler gave a warning about mixing of data types. It has been awhile since I programmed much in C, but when I did I always programmed for zero warnings.

I should do that in VHDL for FPGAs too, but oddly enough, some of the warnings come in the steps that are vendor dependent and warnings are generated by the things the tools do with no way to prevent the warnings other than turning off reporting of warnings. Stupid vendors!

--

Rick
Reply to
rickman

The product of uint16_t 0xffff and uint16_t 0xffff, on a 32-bit int system, is undefined in C. This is because the calculation is done as

32-bit signed, and the value 0xfffe0001 (avoiding typos, I hope) is too big for signed int32_t. The value 0xfffe0001 is 4294901761 in decimal - it is /not/ -65535. Sure, you can fit -65535 into a signed int32_t - or even an int17_t if you like. But you cannot fit 4294901761 into a signed int32_t.

If you have 65535 people, and each of them eat 65535 jelly beans, they have eaten 4294901761 jelly beans in total - they have not eaten -65535 beans.

Remember, this is /C/ (or C++, they work the same at this level) we are discussing. In C, integers are a little odd. They do not behave as two's complement, do not wrap, and cannot be allowed to overflow. It is not like assembly programming, where 0xffff0001 is the same thing as

-65535 with 32-bit registers.

I know you have been an assembly programmer since the dawn of time, but the subtleties of C implicit conversions can trip up even the most experienced programmers.

Reply to
David Brown

David. Will you ever learn to stop digging when in a hole you have put yourself in.

The product of SIGNED multiplication (as you repeatedly repeated) is a SIGNED number and $ffff0001 being a SIGNED number is -65535.

This is completely independent on language, compiler etc. Just basic arithmetic.

Then in NO working compiler would the product of a signed 16 bit being -1 ($ffff) and an unsigned $ffff (65535) - being converted to signed prior to multiplication - will result in a 32 bit overflow, in fact it is quite far from it. IOW, $ffffffff SMUL $0000ffff=$ffff0001 , NO OVERFLOW.

It can result in a 16 bit overflow ONLY.

The overflow you are seeing is not because the 32 bit product overflows, which it does not.

It may be because the unsigned $ffff (65535) overflows when the compiler tries to convert it to a signed 16 bit integer, it does not fit into one. Any properly working compiler wanting the signed 32 bit product we are talking about would sign extend the signed 16 bit to 32, zero extend the unsigned 16 bit to 32 then do the multiplication - in our case the 32 bit result would be about 2^15 far from an overflow.

I would have thought this would be obvious also to compiler users, not just writers - evidently not necessarily so.

I think you must get a 5-th grade arithmetic book and learn about signed numbers, what else can I say to that :D

This has nothing to do with C, D or whatever, it is plain arithmetic.

Dimiter

------------------------------------------------------ Dimiter Popoff, TGI

formatting link

------------------------------------------------------

formatting link

Reply to
Dimiter_Popoff

Um, 4294836225, but the point is well stated.

Reply to
Paul Rubin

Um, so far two of you 5-th grade bound for the signed numbers lesson.

Reply to
Dimiter_Popoff

I believe I have just spotted your problem. My example of the unexpected undefined behaviour in unsigned arithmetic was multiplying /unsigned/ 16-bit 0xffff by /unsigned/ 16-bit 0xffff. Somewhere along the line, you have changed one of these to /signed/ 16-bit 0xffff. Of course there is no such number as signed 16-bit 0xffff - it is outside the range for 16-bit signed integers. But if you mean -1, which will (on almost all systems) be represented by the bit pattern 0xffff, then you are talking about a very different calculation:

uint16_t mult16su(int16_t a, uint16_b) { int32_t a1 = (int32_t) a; int32_t b1 = (int32_t) b; int32_t res1 = a1 * b1; uint16_t res = ((uint32_t) res1) & 0xffff; return res; }

When called with mult16su(-1, 0xffff), a1 is the 32-bit int value -1, while b1 is the 32-bit int value 65535. These can, of course, be multiplied without integer overflow, to give -65535. And when converted to a uint16_t, the result is 0x0001 with no undefined behaviour.

I really should have spotted your misconception in your first post in this thread, where you first wrote "$ffff unsigned expands to 32 bit $0000ffff signed, $ffff signed expands to $ffffffff signed" instead of using unsigned 16-bit values at each stage. We have both failed to read other posts accurately enough here.

Now, with that mistake corrected, you can go back a few posts and see if you now understand my point.

Reply to
David Brown

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.