Uses of a C++ Arithmetic Promotion Header
This is definitely useful -- we use these sorts of things in the math library that I work on for correctly typing intermediate values in expressions. For example, you might have a templated addition operator:
template<typename Atype, typename Btype>
type_promote<Atype, Btype>::type operator+(Atype A, Btype B);
This way, you can write a generic operator that will handle different argument types, and it will return a value of the appropriate type to avoid precision loss in the expression that it appears in. It's also useful (in things like vector sums) for properly declaring internal variables within these operators.
As for the question of what ought to go with these: I just checked in our source code where we define them, and all we have there are just the simple ArithmeticPromotion declaration you describe -- three generic versions to resolve the complex-complex, complex-real, and real-complex variants using the specific real-real ones, and then a list of real-real ones -- about 50 lines of code in all. We don't have any other helper templates with them, and it doesn't (from our usage) look like there are any natural ones that we'd use.
(FWIW, if you don't want to write this yourself, download our source from http://www.codesourcery.com/vsiplplusplus/2.2/download.html, and pull out src/vsip/core/promote.hpp
. That's even in the part of our library that's BSD-licensed, though it doesn't actually say so in the file itself.)
Why are integer types promoted during addition in C?
So it appears that the result of
numberA + 1
was promoted touint32_t
The operands of the addition were promoted to int
before the addition took place, and the result of the addition is of the same type as the effective operands (int
).
Indeed, if int
is 32-bit wide on your compilation platform (meaning that the type that represents uint16_t
has lower “conversion rank” than int
), then numberA + 1
is computed as an int
addition between 1
and a promoted numberA
as part of the integer promotion rules, 6.3.1.1:2 in the C11 standard:
The following may be used in an expression wherever an int or unsigned int may be used: […] An object or expression with an integer type (other than int or unsigned int) whose integer conversion rank is less than or equal to the rank of int and unsigned int.
[…]
If an int can represent all values of the original type […], the value is converted to an int
In your case, unsigned short
which is in all likelihood what uint16_t
is defined as on your platform, has all its values representable as elements of int
, so the unsigned short
value numberA
gets promoted to int
when it occurs in an arithmetic operation.
Bitshift and integer promotion?
The so-called usual arithmetic conversions apply to many binary operators, but not all of them. For example they do not apply to the bit shift operators, &&, ||, comma operator, and assignment operators. This is the rule for the bit shift operators:
6.5.7 ... 3 Semantics ...
The integer promotions are performed on each of the operands. The type of the result is that of the promoted left operand. If the value of the right operand is negative or is greater than or equal to the width of the promoted left operand, the behavior is undefined.
Why is (-1)%(unsigned int) different than (-1)%(int) +(what is it calculating with uint and is casting to int a good solution)
All of C's arithmetic operators (except <<
and >>
which only do this with the first operand) promote both operands to a common type before performing the operation, according the the language's rules for type promotion. Promoting c
(with value -1) to unsigned
performs modular reduction, modulo one plus the max value representable in the type, i.e. one plus UINT_MAX
. The -1 cancels out with the "one plus", and the result is UINT_MAX
, typically 4294967295. Then 4294967295U % 10U
is of course 5.
Result of type cast and bitwise operation in C depends on the order
First of all, none of your code is really reliable and won't do what you expect.
printf
and all other variable argument length functions have a dysfunctional "feature" called the default argument promotions. This means that the actual type of the parameters passed undergo silent promotion. Small integer types (such as char
and short
) get promoted to int
which is signed. (And float gets promoted to double.) Tl;dr: printf
is a nuts function.
Therefore you can cast between various small integer types all you want, there will still be a promotion to int
in the end. This is no problem if you use the correct format specifier for the intended type, but you don't, you use %d
which is for int
.
In addition, the ~
operator, like most operators in C, performs implicit integer promotion of its operand. See Implicit type promotion rules.
That being said, this line ~((~(unsigned short)0) >> 1)
does the following:
Take the literal
0
which is of typeint
and convert tounsigned short
.Implicitly promote that
unsigned short
back toint
through implicit integer promotion.Calculate the bitwise complement of the
int
value0
. This is0xFF...FF
hex,-1
dec, assuming 2's complement.Right shift this
int
by 1. Here you invoke implementation-defined behavior upon shifting a negative integer. C allows this to either result in a logical shift = shift in zeroes, or arithmetic shift = shift in a sign bit. Different result from compiler to compiler and non-portable.You get either
0x7F...FF
in case of logical shift or0xFF...FF
in case of arithmetic shift. In this case it seems to be the latter, meaning you still have decimal-1
after shift.You do bitwise complement of the
0xFF...FF
=-1
and get0
.You cast this to
short
. Still0
.Default argument promotion convert it to
int
. Still0
.%d
expects aint
and therefore prints accordingly.unsigned short
is printed with%hu
andshort
with%hd
. Using the correct format specifier should undo the effect of default argument promotion.
Advice: study implicit type promotion and avoid using bitwise operators on operands that have signed type.
To simply display the lowest 2's complement value of various signed types, you have to do some trickery with unsigned types, since bitwise operations on their signed version are unreliable. Example:
int shift = sizeof(short)*8 - 1; // 15 bits on sane systems
short s = (short) (1u << shift);
printf("%hd\n", s);
This shifts an unsigned int 1u
15 bits, then converts the result of that to short, in some "implementation-defined way", meaning on two's complement systems you'll end up converting 0x8000 to -32768.
Then give printf
the right format specifier and you'll get the expected result from there.
C++ returning more precise of two template arguments from function?
There isn't any built-in support in the form of a library, but you can accomplish this using the conditional (?:
) operator.
In reply to another answer, Johannes Schaub posted a promote<T, U>
template that wraps the logic up quite nicely. With the template, you should be able to write:
template <typename A, typename B>
vector< typename promote<A, B>::type >
operator+(const vector<A> &a, const vector<B> &b)
{
return vector< typename promote<A, B>::type >(a.x+b.x, a.y+b.y, a.z+b.z);
}
Arithmetic overflow warning when trying to allocate memory using new
This creates a size_t
from an unsigned int
, then multiplies the size_t
with an unsigned int
.
outcell = new Cell[size_t{ width / size } * (height / size)];
Depending on the use of width
, height
and size
you might instead consider making these a size_t
.
What will happen if I don't include header files
I know that I get warnings, but the programs runs perfectly.
That is an unfortunate legacy of pre-ANSI C: the language did not require function prototypes, so the standard C allows it to this day (usually, a warning can be produced to find functions called without a prototype).
When you call a function with no prototype, C compiler makes assumptions about the function being called:
- Function's return type is assumed to be
int
- All parameters are assumed to be declared (i.e. no
...
vararg stuff) - All parameters are assumed to be whatever you pass after default promotions, and so on.
If the function being called with no prototype fits these assumptions, your program will run correctly; otherwise, it's undefined behavior.
Adding this instance variable to the header of a C++11 file drives the compiler up the wall. Why?
It has a problem with you keeping a vector of non-const references
std::vector<H&> hs;
I would suggest maintaining either a vector of values or pointers, depending on if you want to own these H
instances or just reference them.
std::vector<H> hs;
std::vector<H*> hs;
Related Topics
Dead Code Detection in Legacy C/C++ Project
Are There Any Better Methods to Do Permutation of String
How Does the Custom Deleter of Std::Unique_Ptr Work
How to Generate the Audio Spectrum Using Fft in C++
Can You Make Custom Operators in C++
How to Append an Int to a String in C++
When Should I Use C++14 Automatic Return Type Deduction
Why Does Gcc Generate 15-20% Faster Code If I Optimize for Size Instead of Speed
Explain Morris Inorder Tree Traversal Without Using Stacks or Recursion
Does Static Constexpr Variable Inside a Function Make Sense
Tools to Find Included Headers Which Are Unused
How to Sort a Std::Map First by Value, Then by Key
Function Overloading Based on Value VS. Const Reference
C++11 Lambda Implementation and Memory Model
Opengl - Mouse Coordinates to Space Coordinates
Linker Error While Linking Boost Log Tutorial (Undefined References)