uint16_t data =x= static_cast<uint16_t>(1) + 1;

142 vistas
Ir al primer mensaje no leído

rian...@gmail.com

no leída,
18 oct 2016, 7:11:27 p.m.18/10/16
para ISO C++ Standard - Future Proposals
Writing a hypervisor in C++, and at least on Intel that are a lot of things that require 8 and 16 bit integers. To my surprise, this generates a warning about conversions:

uint16_t data1 = 1;
uint16_t data2 = data1 + 1;  // warning on possible overflow

The reason is, in C++, when you perform arithmetic, the compiler is allowed to up-cast for you to an int if it results in a performance improvement. So the compiler changes the result of data1 + 1 to an int, and then complains because you could lose data if you store an int back into something smaller, even though the programmer never intended it to be an int in the first place. The following also fails which gets rid of the 1 which is technically an int (although no warnings are fired when you store 1 into something smaller.. only when you use it in arithmetic):

uint16_t data1 = 1;
uint16_t data2 = 1;
uint16_t data3 = data1 + data2; // warning on possible overflow

Now... one might think.. that warning is valid because adding 1 to anything could result in an overflow, except that the same is not true for an int. 

int data1 = 1;
int data2 = 1;
int data3 = data1 + data2; // compiles fine

Has there ever been a proposal to fix this? At least in our code, this one fix would get rid of a LOT of gsl::narrow_casts as it seems to me the warning is a bit overkill as the programmer's intent is valid, it's the compiler doing wonky things.  

Thanks a ton,
- Rian

Ren Industries

no leída,
18 oct 2016, 7:31:57 p.m.18/10/16
para std-pr...@isocpp.org
Isn't this a QOI issue, not a standard one?

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/47e7f79f-8676-4a63-b7d3-09d64219d575%40isocpp.org.

mihailn...@gmail.com

no leída,
19 oct 2016, 6:18:27 a.m.19/10/16
para ISO C++ Standard - Future Proposals,rian...@gmail.com
The first problem is not surprising, because 1 literal is an int. You can fix this with a user defined literal or constructor like uint16(1).

The second problem is because the operation is performed on wider int in case you have 0xffff + 0xffff. It has nothing to do with 1.
I am not sure what tricks the compiler does to silence the warning in the int + int case however.

I any case, I don't believe it can be fixed.

My advise is, to use ints until you need to store the result, then cast it. The performance will be optimal and you will need to cast once.
This what I do.

dgutson .

no leída,
19 oct 2016, 8:31:49 a.m.19/10/16
para std-proposals
On Tue, Oct 18, 2016 at 8:11 PM, <rian...@gmail.com> wrote:
Writing a hypervisor in C++, and at least on Intel that are a lot of things that require 8 and 16 bit integers. To my surprise, this generates a warning about conversions:

uint16_t data1 = 1;
uint16_t data2 = data1 + 1;  // warning on possible overflow

Interestingly, g++ (5.4) does not complain with that snippet, until you do { } initialization:
uint16_t data1{1};
uint16_t data2{data1 + 1};

...then:

warning: narrowing conversion of ‘(((int)data1) + 1)’ from ‘int’ to ‘uint16_t {aka short unsigned int}’ inside { } [-Wnarrowing]
 uint16_t data2{data1 + 1};
                                       ^
Are you using g++ as well? I'm thinking about patching gcc about this. I can't get rid off the warning even by explicitly casting the 1 to uint16_t.

I think that a type promotion due to performance reasons should be considered differently that one explicitly performed, in the way that it should be immediately demoted to the original type. Different is the case of a multiplication.
I'm thinking out loud from the compiler maintainer point of view.
IOW, I think the compiler could do:
constexpr uint16_t add_u16(uint16_t x, uint16_t y)
{
    return uint16_t(uint32_t(x) + uint32_t(y));
}
in this very case, as a QoI thing.

 

The reason is, in C++, when you perform arithmetic, the compiler is allowed to up-cast for you to an int if it results in a performance improvement. So the compiler changes the result of data1 + 1 to an int, and then complains because you could lose data if you store an int back into something smaller, even though the programmer never intended it to be an int in the first place. The following also fails which gets rid of the 1 which is technically an int (although no warnings are fired when you store 1 into something smaller.. only when you use it in arithmetic):

uint16_t data1 = 1;
uint16_t data2 = 1;
uint16_t data3 = data1 + data2; // warning on possible overflow

Now... one might think.. that warning is valid because adding 1 to anything could result in an overflow, except that the same is not true for an int. 

int data1 = 1;
int data2 = 1;
int data3 = data1 + data2; // compiles fine

Has there ever been a proposal to fix this? At least in our code, this one fix would get rid of a LOT of gsl::narrow_casts as it seems to me the warning is a bit overkill as the programmer's intent is valid, it's the compiler doing wonky things.  

Thanks a ton,
- Rian

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.
To view this discussion on the web visit https://groups.google.com/a/isocpp.org/d/msgid/std-proposals/47e7f79f-8676-4a63-b7d3-09d64219d575%40isocpp.org.



--
Who’s got the sweetest disposition?
One guess, that’s who?
Who’d never, ever start an argument?
Who never shows a bit of temperament?
Who's never wrong but always right?
Who'd never dream of starting a fight?
Who get stuck with all the bad luck?

rian...@gmail.com

no leída,
19 oct 2016, 8:41:11 a.m.19/10/16
para ISO C++ Standard - Future Proposals
Yes I am using GCC, and IIRC I think Clang had a similar issue (not idea about VS). And we had the same thing, casting 1 to a unit16_t doesn't change the issue as the result of data1 + data2 == int even though data1 and data2 are both uint16_t. That fact that the compiler is turning this into an int is fine... but it should not warn about a conversion if your storing the result back into the same type, as in that case, the programmer's intent was good, especially when it's fine if all the types are an int or higher. 
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.

David Krauss

no leída,
19 oct 2016, 8:55:09 a.m.19/10/16
para std-pr...@isocpp.org
On 2016–10–19, at 8:31 PM, dgutson . <daniel...@gmail.com> wrote:



On Tue, Oct 18, 2016 at 8:11 PM, <rian...@gmail.com> wrote:
Writing a hypervisor in C++, and at least on Intel that are a lot of things that require 8 and 16 bit integers. To my surprise, this generates a warning about conversions:

uint16_t data1 = 1;
uint16_t data2 = data1 + 1;  // warning on possible overflow

Interestingly, g++ (5.4) does not complain with that snippet, until you do { } initialization:

I tried GCC and Clang with -Wall -Wextra -Woverflow -Wnarrowing and couldn’t get any diagnoses.

With braces, the narrowing conversion makes the program ill-formed. It is conforming to issue a warning for an ill-formed program, but it is nonconforming to be quiet. The standard doesn’t usually differentiate between error messages and warning messages.

To silence the warning requires a static_cast on the sum: data2{ static_cast< uint16_t >( data1 + 1 ) }.

It would be nice to redo C++ without integer promotion, but perhaps allowing the same optimization as a matter of undefined overflow, much as floating-point computations don’t have guaranteed imprecision. Unfortunately, we’re pretty much stuck with it.

rian...@gmail.com

no leída,
19 oct 2016, 8:59:33 a.m.19/10/16
para ISO C++ Standard - Future Proposals
These are the flags that we are using:

-Wall -Wextra -Wpedantic -Wctor-dtor-privacy -Wshadow -Wnon-virtual-dtor -Wold-style-cast -Wcast-align -Woverloaded-virtual -Wconversion -Wsign-conversion -DGSL_THROW_ON_CONTRACT_VIOLATION -fpic -fexceptions -fstack-protector-strong -mstackrealign -mmmx -msse -msse2 -msse3 -mssse3 -msse4.1 -msse4.2 -msse4 -mavx -maes -ffreestanding -mno-red-zone

I think -Wconversion is the offending flag. 

- Rian

dgutson .

no leída,
19 oct 2016, 8:59:53 a.m.19/10/16
para std-proposals
On Wed, Oct 19, 2016 at 9:55 AM, David Krauss <pot...@gmail.com> wrote:

On 2016–10–19, at 8:31 PM, dgutson . <daniel...@gmail.com> wrote:



On Tue, Oct 18, 2016 at 8:11 PM, <rian...@gmail.com> wrote:
Writing a hypervisor in C++, and at least on Intel that are a lot of things that require 8 and 16 bit integers. To my surprise, this generates a warning about conversions:

uint16_t data1 = 1;
uint16_t data2 = data1 + 1;  // warning on possible overflow

Interestingly, g++ (5.4) does not complain with that snippet, until you do { } initialization:

I tried GCC and Clang with -Wall -Wextra -Woverflow -Wnarrowing and couldn’t get any diagnoses.

With braces, the narrowing conversion makes the program ill-formed.

Is this ill-formed?

uint16_t data2{data1 + uint16_t(1)};

Accordint to what paragraph?


 
It is conforming to issue a warning for an ill-formed program, but it is nonconforming to be quiet. The standard doesn’t usually differentiate between error messages and warning messages.

To silence the warning requires a static_cast on the sum: data2{ static_cast< uint16_t >( data1 + 1 ) }.

It would be nice to redo C++ without integer promotion, but perhaps allowing the same optimization as a matter of undefined overflow, much as floating-point computations don’t have guaranteed imprecision. Unfortunately, we’re pretty much stuck with it.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

rian...@gmail.com

no leída,
19 oct 2016, 9:03:33 a.m.19/10/16
para ISO C++ Standard - Future Proposals
Here is a an actual example from my project:


If I change this code to the following:

void
serial_port_intel_x64::set_data_bits(data_bits_t bits) noexcept
{
    auto reg = portio::inb(m_port + LINE_CONTROL_REG);

    reg &= gsl::narrow_cast<decltype(reg)>(~LINE_CONTROL_DATA_MASK);
    reg |= gsl::narrow_cast<decltype(reg)>(bits & LINE_CONTROL_DATA_MASK);

    portio::outb(m_port + LINE_CONTROL_REG, reg);
}

I get this:

/home/user/hypervisor/bfvmm/src/serial/src/serial_port_intel_x64.cpp: In member function ‘void serial_port_intel_x64::set_data_bits(serial_port_intel_x64::data_bits_t)’:
/home/user/hypervisor/bfvmm/src/serial/src/serial_port_intel_x64.cpp:123:9: error: conversion to ‘unsigned char’ from ‘int’ may alter its value [-Werror=conversion]
     reg &= gsl::narrow_cast<decltype(reg)>(~LINE_CONTROL_DATA_MASK);
         ^
/home/user/hypervisor/bfvmm/src/serial/src/serial_port_intel_x64.cpp:124:9: error: conversion to ‘unsigned char’ from ‘int’ may alter its value [-Werror=conversion]
     reg |= gsl::narrow_cast<decltype(reg)>(bits & LINE_CONTROL_DATA_MASK);
         ^
cc1plus: all warnings being treated as errors



On Wednesday, October 19, 2016 at 6:59:53 AM UTC-6, dgutson wrote:
On Wed, Oct 19, 2016 at 9:55 AM, David Krauss <pot...@gmail.com> wrote:

On 2016–10–19, at 8:31 PM, dgutson . <daniel...@gmail.com> wrote:



On Tue, Oct 18, 2016 at 8:11 PM, <rian...@gmail.com> wrote:
Writing a hypervisor in C++, and at least on Intel that are a lot of things that require 8 and 16 bit integers. To my surprise, this generates a warning about conversions:

uint16_t data1 = 1;
uint16_t data2 = data1 + 1;  // warning on possible overflow

Interestingly, g++ (5.4) does not complain with that snippet, until you do { } initialization:

I tried GCC and Clang with -Wall -Wextra -Woverflow -Wnarrowing and couldn’t get any diagnoses.

With braces, the narrowing conversion makes the program ill-formed.

Is this ill-formed?

uint16_t data2{data1 + uint16_t(1)};

Accordint to what paragraph?


 
It is conforming to issue a warning for an ill-formed program, but it is nonconforming to be quiet. The standard doesn’t usually differentiate between error messages and warning messages.

To silence the warning requires a static_cast on the sum: data2{ static_cast< uint16_t >( data1 + 1 ) }.

It would be nice to redo C++ without integer promotion, but perhaps allowing the same optimization as a matter of undefined overflow, much as floating-point computations don’t have guaranteed imprecision. Unfortunately, we’re pretty much stuck with it.

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposal...@isocpp.org.

To post to this group, send email to std-pr...@isocpp.org.

Barry Revzin

no leída,
19 oct 2016, 9:27:51 a.m.19/10/16
para ISO C++ Standard - Future Proposals

Is this ill-formed?

uint16_t data2{data1 + uint16_t(1)};

Accordint to what paragraph?



[dcl.init.list]/3.7:

— Otherwise, if the initializer list has a single element of type E and either T is not a reference type or its
referenced type is reference-related to E, the object or reference is initialized from that element (by
copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization); if a
narrowing conversion (see below) is required to convert the element to T, the program is ill-formed.
[ Example:
int x1 {2}; // OK
int x2 {2.0}; // error: narrowing
—end example ]

Where a narrowing conversion includes conversions

— from an integer type or unscoped enumeration type to an integer type that cannot represent all the
values of the original type, except where the source is a constant expression whose value after integral
promotions will fit into the target type. 

rian...@gmail.com

no leída,
19 oct 2016, 9:32:43 a.m.19/10/16
para ISO C++ Standard - Future Proposals
Does that explain why this causes a conversion warning?

    auto reg = portio::inb(m_port + LINE_CONTROL_REG);

    reg &= gsl::narrow_cast<decltype(reg)>(~LINE_CONTROL_DATA_MASK);
    reg |= gsl::narrow_cast<decltype(reg)>(bits & LINE_CONTROL_DATA_MASK);

Currently, my code does this to get rid of the conversion warning, which should (I thought) identical:

    auto reg = portio::inb(m_port + LINE_CONTROL_REG);

    reg = reg & gsl::narrow_cast<decltype(reg)>(~LINE_CONTROL_DATA_MASK);
    reg = reg | gsl::narrow_cast<decltype(reg)>(bits & LINE_CONTROL_DATA_MASK);

It might just a be a compiler bug, but googling the topic, others have seen this, and the answers I have seen have been quotes to the spec suggesting this is intended which is why I asked if someone had attempted to write a proposal to address this as it seems like there are a couple of edge cases here that just need to be cleaned up. 

- Rian

dgutson .

no leída,
19 oct 2016, 9:33:33 a.m.19/10/16
para std-proposals
On Wed, Oct 19, 2016 at 10:27 AM, Barry Revzin <barry....@gmail.com> wrote:

Is this ill-formed?

uint16_t data2{data1 + uint16_t(1)};

Accordint to what paragraph?



[dcl.init.list]/3.7:

— Otherwise, if the initializer list has a single element of type E and either T is not a reference type or its
referenced type is reference-related to E, the object or reference is initialized from that element (by
copy-initialization for copy-list-initialization, or by direct-initialization for direct-list-initialization); if a
narrowing conversion (see below) is required to convert the element to T, the program is ill-formed.
[ Example:
int x1 {2}; // OK
int x2 {2.0}; // error: narrowing
—end example ]

Where a narrowing conversion includes conversions


What about adding an amendment to the following clause ("except" part) to consider this case, something like...
 
— from an integer type or unscoped enumeration type to an integer type that cannot represent all the
values of the original type, except where the source is a constant expression whose value after integral
promotions will fit into the target type

.. and optionally an arithmetic operation where the operands are such constant expression and an operand of the T?

(sorry my "std English"). I think we could improve the clause because beyond what it rules, this scenario is a valid conversion. 

 

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Thiago Macieira

no leída,
19 oct 2016, 2:09:17 p.m.19/10/16
para std-pr...@isocpp.org
On terça-feira, 18 de outubro de 2016 16:11:27 PDT rian...@gmail.com wrote:
> Writing a hypervisor in C++, and at least on Intel that are a lot of things
> that require 8 and 16 bit integers. To my surprise, this generates a
> warning about conversions:
>
> uint16_t data1 = 1;
> uint16_t data2 = data1 + 1; // warning on possible overflow
>
> The reason is, in C++, when you perform arithmetic, the compiler is allowed
> to up-cast for you to an int if it results in a performance improvement. So

Actually, the compiler is required to perform the cast to int, due to integer
promotion rules. But the operation doesn't change either way.

If we performed the addition in 16-bit unsigned, the overflow is well defined
and adding 1 to 0xffff is expected and required to result in 0. If we perform
the addition on 32-bit, then adding 1 to 0xffff results in 0x10000, which then
gets truncated to 16 bit in a well-defined form and also results in 0.

It's even the same in assembly:

movl $1, %reg1
addw %reg1w, %reg2w

and

movl $1, %reg1
addl %reg1, %reg2

Even if we started with %reg2 = 0xffff, the end result in %reg2w is 0. The
only difference is that the addw instruction would set the carry flag, whereas
the addl instruction would clear it and set bit 16 on %reg2.

An important difference is performance. The addw instruction would leave the
high 32 bits of %reg2 unchanged, which can cause a pipeline stall due to a
data dependency on what was there.

> Has there ever been a proposal to fix this? At least in our code, this one
> fix would get rid of a LOT of gsl::narrow_casts as it seems to me the
> warning is a bit overkill as the programmer's intent is valid, it's the
> compiler doing wonky things.

There's nothing to be fixed, as far as the standard is concerned.

You have a QoI issue. Please talk to your compiler vendor.

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center

rian...@gmail.com

no leída,
19 oct 2016, 2:11:40 p.m.19/10/16
para ISO C++ Standard - Future Proposals
Awesome, yeah that's what I wanted to clarify as others have blamed it on the spec, so i wanted to get this clarified before reporting a bug. 

Thanks,
- Rian

dgutson .

no leída,
19 oct 2016, 3:12:24 p.m.19/10/16
para std-proposals
On Wed, Oct 19, 2016 at 3:11 PM, <rian...@gmail.com> wrote:
Awesome, yeah that's what I wanted to clarify as others have blamed it on the spec, so i wanted to get this clarified before reporting a bug. 

Sorry for the spam to others. Could you please paste here the link to the bugzilla entry so we could watch the issue and/or get assigned?

 

--
You received this message because you are subscribed to the Google Groups "ISO C++ Standard - Future Proposals" group.
To unsubscribe from this group and stop receiving emails from it, send an email to std-proposals+unsubscribe@isocpp.org.
To post to this group, send email to std-pr...@isocpp.org.

Myriachan

no leída,
19 oct 2016, 4:07:31 p.m.19/10/16
para ISO C++ Standard - Future Proposals
On Wednesday, October 19, 2016 at 11:09:17 AM UTC-7, Thiago Macieira wrote:
Actually, the compiler is required to perform the cast to int, due to integer
promotion rules. But the operation doesn't change either way.


The promotion to int is also very important to consider in avoiding a certain case of undefined behavior:

std::uint16_t x = 0xFFFF;
x *= x;

Melissa

Thiago Macieira

no leída,
19 oct 2016, 7:02:57 p.m.19/10/16
para std-pr...@isocpp.org
Indeed, this causes a signed integer overflow, which is UB.

If you'd written:

x *= unsigned(x);

Then this is no longer UB.

Andrey Semashev

no leída,
19 oct 2016, 8:06:25 p.m.19/10/16
para std-pr...@isocpp.org
On 10/20/16 02:02, Thiago Macieira wrote:
> Em quarta-feira, 19 de outubro de 2016, às 13:07:31 PDT, Myriachan escreveu:
>> On Wednesday, October 19, 2016 at 11:09:17 AM UTC-7, Thiago Macieira wrote:
>>> Actually, the compiler is required to perform the cast to int, due to
>>> integer
>>> promotion rules. But the operation doesn't change either way.
>>
>> The promotion to int is also very important to consider in avoiding a
>> certain case of undefined behavior:
>>
>> std::uint16_t x = 0xFFFF;
>> x *= x;
>
> Indeed, this causes a signed integer overflow, which is UB.
>
> If you'd written:
>
> x *= unsigned(x);
>
> Then this is no longer UB.

I've always wondered why the language had allowed the implicit
conversion to int in such cases. I mean, if it didn't the implementation
could have compiled the code to use full-width 32-bit instructions and
then slice the result and have the same performance anyway. But that
wouldn't introduce problems like in the OP or the UB above.

Thiago Macieira

no leída,
20 oct 2016, 12:36:27 a.m.20/10/16
para std-pr...@isocpp.org
Em quinta-feira, 20 de outubro de 2016, às 03:06:22 PDT, Andrey Semashev
escreveu:
> >> std::uint16_t x = 0xFFFF;
> >> x *= x;
> >
> > Indeed, this causes a signed integer overflow, which is UB.
> >
> > If you'd written:
> > x *= unsigned(x);
> >
> > Then this is no longer UB.
>
> I've always wondered why the language had allowed the implicit
> conversion to int in such cases. I mean, if it didn't the implementation
> could have compiled the code to use full-width 32-bit instructions and
> then slice the result and have the same performance anyway. But that
> wouldn't introduce problems like in the OP or the UB above.

The reason it does that is that most architectures (especially the RISC ones)
can only execute operations on a single register width. So the standard says
that any operation operates on rank of at least that of int/unsigned. Smaller
types (types of lesser rank) are used only for storage.

Also, the OP didn't have a problem.

Andrey Semashev

no leída,
20 oct 2016, 4:16:00 a.m.20/10/16
para std-pr...@isocpp.org
On 10/20/16 07:36, Thiago Macieira wrote:
> Em quinta-feira, 20 de outubro de 2016, às 03:06:22 PDT, Andrey Semashev
> escreveu:
>>>> std::uint16_t x = 0xFFFF;
>>>> x *= x;
>>>
>>> Indeed, this causes a signed integer overflow, which is UB.
>>>
>>> If you'd written:
>>> x *= unsigned(x);
>>>
>>> Then this is no longer UB.
>>
>> I've always wondered why the language had allowed the implicit
>> conversion to int in such cases. I mean, if it didn't the implementation
>> could have compiled the code to use full-width 32-bit instructions and
>> then slice the result and have the same performance anyway. But that
>> wouldn't introduce problems like in the OP or the UB above.
>
> The reason it does that is that most architectures (especially the RISC ones)
> can only execute operations on a single register width. So the standard says
> that any operation operates on rank of at least that of int/unsigned. Smaller
> types (types of lesser rank) are used only for storage.

That doesn't preclude what I suggested.

> Also, the OP didn't have a problem.

I think, warnings with an innocent looking code and having to sprinkle
casts everywhere is a problem. I faced this problem myself. The fact
that the warnings are the result of the behavior allowed by the standard
indicates that this is not entirely QoI. Integers are hard in C++, much
too hard IMO.

Thiago Macieira

no leída,
20 oct 2016, 11:02:12 a.m.20/10/16
para std-pr...@isocpp.org
Em quinta-feira, 20 de outubro de 2016, às 11:15:56 PDT, Andrey Semashev
escreveu:
> > The reason it does that is that most architectures (especially the RISC
> > ones) can only execute operations on a single register width. So the
> > standard says that any operation operates on rank of at least that of
> > int/unsigned. Smaller types (types of lesser rank) are used only for
> > storage.
>
> That doesn't preclude what I suggested.

I think it does. The point is that the operation is always done on int on
those machines, whether you want it or not (and RISC machines are still the
majority, despite my employer's best efforts). So the standard says that the
compiler does not have to emulate whatever behaviour would be necessary for
lesser-ranked types.

I can't think of which operation would be different on 16-bit than on 32-bit,
but that doesn't mean one doesn't exist.

> > Also, the OP didn't have a problem.
>
> I think, warnings with an innocent looking code and having to sprinkle
> casts everywhere is a problem. I faced this problem myself. The fact
> that the warnings are the result of the behavior allowed by the standard
> indicates that this is not entirely QoI. Integers are hard in C++, much
> too hard IMO.

Sorry, let me be stricter: the OP didn't have a problem relating to the
*standard*. Melissa dd point out a case where a problem would exist, but it
was not one found in the OP's original code. I also agree that there are some
"gotchas" with integers in C++, some of them serious (like Melissa's example).

Myriachan

no leída,
27 oct 2016, 5:54:17 p.m.27/10/16
para ISO C++ Standard - Future Proposals
On Thursday, October 20, 2016 at 8:02:12 AM UTC-7, Thiago Macieira wrote:
Indeed, this causes a signed integer overflow, which is UB.

If you'd written:

        x *= unsigned(x);

Then this is no longer UB.
 

I recommend a different solution, one that someone on Stack Overflow pointed out:

x = 1u * x * x;

Then you don't have to worry about "unsigned" being of smaller size than "decltype(x)".  This promotes to the higher-ranked of "unsigned" and "decltype(x)", both of which are unsigned.


I think it does. The point is that the operation is always done on int on
those machines, whether you want it or not (and RISC machines are still the
majority, despite my employer's best efforts). So the standard says that the
compiler does not have to emulate whatever behaviour would be necessary for
lesser-ranked types.


I like promotion as a concept, but to me, promoting from unsigned to signed is broken behavior.  It should stay the same signedness.  But it's decades too late to do anything about that.
 
I can't think of which operation would be different on 16-bit than on 32-bit,
but that doesn't mean one doesn't exist.


In 16-bit MS-DOS, my undefined behavior case is just:
std::uint8_t x = 0xFF;
x *= x;

Melissa
Responder a todos
Responder al autor
Reenviar
0 mensajes nuevos