Significance of -Werror=old-style-cast? - c++

I'm using code that casts some ints to floats for division.
size_t a;
uint8_t b, c;
a = (float)b / (float)c;
I was compiling with warning flags enabled and I got one for 'old cast'. Is there a better or proper way I should be casting these things? If so, how?

Old style casts are "C-style" casts.
-Werror=old-style-cast turns the usage of C-style casts into errors.
You should use the C++ casts.
Here you can use a static_cast :
size_t a; uint8_t b, c;
a = static_cast<float>(b) / static_cast<float>(c);

Related

Why is there a narrowing conversion warning from int to short when adding shorts? (C++)

I have a code similar to this for the following array:
long int N = 424242424242; //random number
short int* spins = new short int spins[N];
std::fill(spins, spins+N, 1);
Now let's suppose for some reason I want to add a couple of elements of that array into a short int called nn_sum:
short int nn_sum = spins[0] + spins[1];
However, when I do this on CLion IDE, Clang-Tidy marks it yellow and tells me:
Clang-Tidy: Narrowing conversion from 'int' to signed type 'short' is implementation-defined
Why is this happening? Why is there any narrowing at all? Does C++ convert the shorts to ints when adding them? If so why, and is there something I can do to make it work better? Maybe even ditch the shorts entirely?
Keep in mind that I have code like this in a very computationally intensive part of the application so I want to make it as efficient as possible. Any other suggestion would also be appreciated.
This happens because of integer promotion. The result of adding two short values is not short, but int.
You can check this with cppinsights.io:
short a = 1;
short b = 2;
auto c = a + b; // c is int
Demo: https://cppinsights.io/s/68e27bd7

Correctly converting floating point in C++

What would be the correct/recommended way of telling the C++ compiler "only warn me of floating point conversions that I'm not aware of"?
In C, I would enable the warnings related to floating point conversions, and then I would use explicit C-style casts to silence warnings related to the conversions that are under control.
For example, computing a*a*a - b*b is quite prone to overflow in single precision floating point, so you might wish to compute it in double precision and only go single precision later:
double a = 443620.52;
double b = 874003.01;
float c = (float)(a*a*a - b*b);
The above C-style explicit cast would silence the compiler warning about the conversion from double to float.
Reading C++ documentation about casts, I get to the conclusion that the correct way of doing this in C++ would be as follows:
double a = 443620.52;
double b = 874003.01;
float c = static_cast<float>(a*a*a - b*b);
But, is this really the correct way of doing this in C++?
I understand the rationale behind the static_cast syntax being ugly on purpose, so that you avoid casts completely if possible.
Yes, I can omit the explicit cast to float. But then I need to disable compiler warnings telling me of precision loss (or otherwise I'd get a number of irrelevant warnings that would make it difficult to notice really relevant warnings). And if I disable fp-related compiler warnings, I'd lose the possibility of being warned when I'm mistakenly losing precision in other code places.
So, what's the correct approach for floating point conversions in C++?
Yes
float c = static_cast<float>(a*a*a - b*b);
is the correct way of explicitly casting to float in C++. You can also do:
float c = (float)(a*a*a - b*b);
but using a "C-style" cast like that is bad style because static_cast will hide rather fewer errors than C-style.
Alternatively, if you are doing this a lot, you can define a function:
inline float flt(double d){return static_cast<float>(d);}
and then you can write:
float c = flt(a*a*a - b*b);
which is even more compact than the original C (and will be optimized away to nothing).
As far as I am aware, there are three different ways to avoid the warning:
C-style cast
static_cast
Constructor-style cast (e.g. float c = float(a*a*a-b*b))
In the code example below, c1, c2 and c3 avoid the warnings:
int main()
{
double a = 443620.52;
double b = 874003.01;
// These three versions avoid the conversion warnings:
float c1 = (float)(a*a*a - b*b);
float c2 = static_cast<float>(a*a*a - b*b);
float c3 = float(a*a*a - b*b);
// Only these two give conversion warnings:
float c4(a*a*a - b*b);
float c5 = a*a*a - b*b;
(void)c1; // Just to avoid unused-variable warnings
(void)c2;
(void)c3;
(void)c4;
(void)c5;
}
Only c4 and c5 trigger a warning. Check the live demo to see the results.

How to convert a float to an int in modern C++

As strange as it may seems, I can't find how to cleanly convert a float to an int.
This technique
int int_value = (int)(float_value + 0.5);
triggers a
warning: use of old-style cast
in gcc.
So, what is the modern-style, simple way to convert a float to an int ? (I accept the loss of precision of course)
As Josh pointed out in the comments, + 0.5 is not very reliable. For extra security you could combine a static_cast with std::round like so:
int int_value = static_cast<int>(std::round(float_value));
For the casting part, see this excellent post for an explanation.
try:
int int_value = static_cast<int>(float_value + 0.5);
FYI: different casts in C++ gave a very good explanation about those 4 casts introduced in C++.
You could also consider
int int_value = boost::lexical_cast<int>(float_value);
lexical_cast has the benefit of working for all primitive types, and stl strings etc. It also means you don't have to do the (float_value + 0.5) stuff.

Casting an array of unsigned chars to an array of floats

What is the best way of converting a unsigned char array to a float array in c++?
I presently have a for loop as follows
for (i=0 ;i< len; i++)
float_buff[i]= (float) char_buff[i];
I also need to reverse the procedure, i.e convert from unsigned char to float (float to 8bit conversion)
for (i=0 ;i< len; i++)
char_buff[i]= (unsigned char) float_buff[i];
Any advice would be appreciated
Thanks
I think the best way is to use a function object:
template <typename T> // T models Any
struct static_cast_func
{
template <typename T1> // T1 models type statically convertible to T
T operator()(const T1& x) const { return static_cast<T>(x); }
};
followed by:
std::transform(char_buff, char_buff + len, float_buff, static_cast_func<float>());
std::transform(float_buff, float_buff + len, char_buff, static_cast_func<unsigned char>());
This is the most readable because it says what is being done in English: transforming a sequence into a different type using static casting. And future casts can be done in one line.
Your solution is pretty much the best option, however, I would consider switching to:
char_buff[i]= static_cast<unsigned char>(float_buff[i]);
The cast is automatic so you don't need to make it explicit.
But you can use the standard algorithms:
std::copy(char_buff,char_buff+len,float_buff);
Converting back from float to char there is a potential loss of information. So you need to be more explicit.
std::transform(float_buff,float_buff+len,char_buff,MyTransform());
Here we use the class MyTransform which should have an operator() that takes a float and returns a char. That should be trivial to impliment.
Your solution seems right, though on the way back, you might lose the floating digits in the casting.
For what purpose are you doing this? Shoving a float into a char doesn't really make sense. On most platforms a float will be 4 bytes and represent a floating point number, where as a char will be 1 byte and often represents a single character. You'll lose 3 bytes of data trying to shove a float into a char, right?
Your first loop doesn't require a cast. You can implicitly convert from one type (e.g., unsigned char) to a wider type (e.g., float). Your second loop should use static_cast:
for (i=0; i< len; i++)
char_buff[i]= static_cast<unsigned char>(float_buff[i]);
We use static_cast to explicitly tell the compiler to do the conversion to a narrower type. If you don't use the cast, your compiler might warn you that the conversion could lose data. The presence of the cast operator means that you understand you might lose data precision and you're ok with it. This is not an appropriate place to use reinterpret_cast. With static_cast, you at least have some restrictions on what conversions you can do (e.g., it probably won't let you convert a Bird* to a Nuclear_Submarine*). reinterpret_cast has no such restrictions.
Also, here's what Bjarne Stroustrup has to say about this subject.
If you are dealing with very large arrays and performance is essential then the following may prove slightly more efficient:
float *dst = float_buff;
unsigned char *src = char_buff;
for (i=0; i<len; i++) *dst++ = (float)*src++;
No one has mentioned this, but if you're doing any arithmetic with the floats, you may want to round instead of truncate... if you have the char 49, and it gets turned into 4.9E1, after some arithmetic, it might turn into 4.89999999E1 which will turn into 48 when you turn it back into a char.
If you're not doing anything with the float, this shouldn't be a problem, but then why do you need it as a float in the first place?

How to get the result of strlen into an int without a warning when compiling with /Wp64

int l = strlen(s);
warning C4244: '=' : conversion from '__w64 int' to 'int', possible loss of data
I need to replace strlen with an inline function
int l = new_strlen(s);
But how do I portably get the result of the strlen into the int without a warning, and without using pragmas? I can guarantee there aren't more than 2 billion characters in my string!
All the obvious things like reinterpret_cast, static_cast also produce errors or warnings.
EDIT: Argh. a c-style cast: (int) does work. I had been convinced that it did not.
const char * str = "Hello";
int len = static_cast< int >( strlen( str ) );
return len;
This code doesn't produce any error or warning even on Warning Level 4 (VS2005).
What compiler do you use?
Also note that /Wp64 is deprecated in VS2008; apparently it's not reliable.
Cast it:
int i = (int) strlen(s);
Or don't use a signed int. The return value of strlen() is unsigned.
In cases where you really have a good reason to truncate pointers, you can make /Wp64 accept your code by stacking multiple casts. These cases are rare. One example: device drivers for legacy PCI devices, doing DMA, with memory allocated below the 4GB limit. (Note: there is also the PtrToUlong() macro, which will make your intentions clearer.)
This single cast will produce a warning:
const char* p = "abc";
unsigned int u = reinterpret_cast<unsigned int>(p);
wp64.cpp(10) : warning C4311: 'reinterpret_cast' : pointer truncation from 'const char *' to 'unsigned int'
But these stacked casts will not:
const char* p = "abc";
unsigned int u = static_cast<unsigned int>(reinterpret_cast<uintptr_t>(p));
I'm not able to reproduce your warning with the version of the compiler that I have installed, but I suspect that your problem is related to the fact that you're casting a 64-bit unsigned size_t into a 32-bit signed int.
You might have better luck if you stack multiple casts to do the 64-bit to 32-bit conversion and the unsigned-to-signed conversion:
const char* s = "abcdef";
int l = static_cast<int>(static_cast<intptr_t>(strlen(s)));
Also, if you build both x86 and x64 binaries, you can disable /Wp64 for your 32-bit builds so that you don't have to annotate any types with __w64. Using /Wp64 for your 64-bit builds will catch a lot of bugs.
if you understand a warning, its perfectly acceptable to disable the warning instead of stacking casts or whatever other confusing mess as a workaround.
A pragma warning directive with the
suppress specifier suppresses the
warning only for the line of code that
immediately follows the #pragma
warning statement.
#pragma warning( suppress : 6001 )
arr[i+1] = 0; // Warning 6001 is suppressed
j++; // Warning 6001 is reported
(msvc specific)
I need to replace strlen with an
inline function int l = new_strlen(s);
Note that in VC++, strlen is automatically replaced by a inline version when you build an optimized version.