correctly fixing conversion and loss of data warnings? - c++

I have a class called PointF and it has a constructor that takes a Point, and I keep getting "possible loss of data warnings". How can I show that my intention is in fact to make a float value into an int, among other tings? I tried static_cast and (float) but they did not fix the warning.
For example:
int curPos = ceil(float(newMouseY / font.getLineHeight())) ; //float to int
And
outputChars[0] = uc; //converting from size_t to char

A cast should do the trick; that says "explicitly make this type into that type", which is generally pretty silly for a compiler to warn for:
int curPos = static_cast<int>(ceil(float(newMouseY / font.getLineHeight())));
Or:
outputChars[0] = static_cast<char>(uc);
Make sure the casts you tried were akin to that. You say "I tried ...(float)" which leads me to believe you tried something like this:
int curPos = (float)(ceil(float(newMouseY / font.getLineHeight())));
Which does nothing. The type of the expression is already a float, what would casting it to the same type do? You need to cast it to the destination type.
Keep in mind casts are generally to be avoided. In your first snippet, the cast is sensible because when you quantize something you necessarily need to drop information.
But your second cast is not. Why is uc a size_t in the first place? What happens when the cast does drop information? Is that really a good idea?

You need to cast the result of ceil, preferably with a static_cast.

you may have to use an explicit cast, i.e.
int curPos = int(ceil(...));

You must cast your variable to normally good way change type of her. And if you trying convert size_t to char, then you trying save 4 bytes into 1 byte, data lost is a normal thing in this way.

Related

Converting Integer Types

How does one convert from one integer type to another safely and with setting off alarm bells in compilers and static analysis tools?
Different compilers will warn for something like:
int i = get_int();
size_t s = i;
for loss of signedness or
size_t s = get_size();
int i = s;
for narrowing.
casting can remove the warnings but don't solve the safety issue.
Is there a proper way of doing this?
You can try boost::numeric_cast<>.
boost numeric_cast returns the result of converting a value of type Source to a value of type Target. If out-of-range is detected, an exception is thrown (see bad_numeric_cast, negative_overflow and positive_overflow ).
How does one convert from one integer type to another safely and with setting off alarm bells in compilers and static analysis tools?
Control when conversion is needed. As able, only convert when there is no value change. Sometimes, then one must step back and code at a higher level. IOWs, was a lossy conversion needed or can code be re-worked to avoid conversion loss?
It is not hard to add an if(). The test just needs to be carefully formed.
Example where size_t n and int len need a compare. Note that positive values of int may exceed that of size_t - or visa-versa or the same. Note in this case, the conversion of int to unsigned only happens with non-negative values - thus no value change.
int len = snprintf(buf, n, ...);
if (len < 0 || (unsigned)len >= n) {
// Handle_error();
}
unsigned to int example when it is known that the unsigned value at this point of code is less than or equal to INT_MAX.
unsigned n = ...
int i = n & INT_MAX;
Good analysis tools see that n & INT_MAX always converts into int without loss.
There is no built-in safe narrowing conversion between int types in c++ and STL. You could implement it yourself using as an example Microsoft GSL.
Theoretically, if you want perfect safety, you shouldn't be mixing types like this at all. (And you definitely shouldn't be using explicit casts to silence warnings, as you know.) If you've got values of type size_t, it's best to always carry them around in variables of type size_t.
There is one case where I do sometimes decide I can accept less than 100.000% perfect type safety, and that is when I assign sizeof's return value, which is a size_t, to an int. For any machine I am ever going to use, the only time this conversion might lose information is when sizeof returns a value greater than 2147483647. But I am content to assume that no single object in any of my programs will ever be that big. (In particular, I will unhesitatingly write things like printf("sizeof(int) = %d\n", (int)sizeof(int)), explicit cast and all. There is no possible way that the size of a type like int will not fit in an int!)
[Footnote: Yes, it's true, on a 16-bit machine the assumption is the rather less satisfying threshold that sizeof won't return a value greater than 32767. It's more likely that a single object might have a size like that, but probably not in a program that's running on a 16-bitter.]

Have to cast value in assignment

I've got some c++ code that's requiring me to cast an immediate in an assignment statement. The casting makes the code more difficult to read and I was hoping there was a way around this.
uint64_t shifted_val = (uint64_t)1 << 50;
If I write this code without the cast, shifted_val gets set to 0, I assume because it's treating the 1 immediate as a 32-bit value. Is there something I'm missing so that I can write this without casting?
You can do:
uint64_t shifted_val = 1ull << 50;
If you think the syntax is also close to casting then you can do:
uint64_t a = 1;
uint64_t shifted_val = a << 50;
One way to do it is to adopt a habit of performing the calculations within the recipient variable itself
uint64_t shifted_val = 1;
shifted_val <<= 50;
This will solve the issue naturally, without requiring you to hardcode additional type references into the expression (like type casts or type-specific suffixes).
The constant needs to be treated as a 64 bit value, so there needs to be some way of specifying that.
You could specify it as 1ULL, which tells the compiler the constant is a unsigned long long, however that may not necessarily be 64 bit, so you're better off with the cast to be more portable.

Casting long int as a struct pointer

I know this is a rather noobish question, but no amount of googling or permutations of code seem to work.
I have a structure which is defined like this.
typedef struct
{
int rate;
int duration;
} DummyStructure;
Now, i try to use code similar to this.
//
DummyStructure* structure;
DummyStructure* structure2;
long int point;
//
structure = (DummyStructure*)malloc(sizeof(DummyStructure));
structure->rate = 19;
structure->duration = 92;
point = (long int)&structure;
// now i'd like to set structure2 to the same memory location as 1.
// point is the 8-byte int location (i assume?) of structure.
// so naturally i'd assume that by casting as a DummyStructure pointer
// that long int would act as a pointer to that 1.
// It doesn't.
structure2 = (DummyStructure*)point;
I stress that i've tried every permutation of ** and * that is possible. I just don't get it. Either it doesn't compile, or it does, and when it does i end up with seemingly random numbers for the fields contained in structure2. I assume that somehow i'm winding up with an incorrect memory location, but how else can you get it except from using the &?
I have the memory location, right? How do i set the structure to that location?
EDIT; I forgot to mention (and subsequent answers have asked) but i'm intending to use this to wrap libvorbis for jni. Using jni means that i can't pass-back any of the structs that libvorbis does, but it requires them for its core functions. Therefore my wrapper is going to use vorbis directly to make the structs, and i pass back to java the pointer to them so that when i need to fill the buffer with more sound, i can simply re-reference the struct objects from the integer value of the pointer.
Why are you trying to cast pointers to integers and back? Is it just to learn, to figure something out, to work around some (untold) restriction, or what? It's a rather strange thing to be doing in a "plain" program such as this, as there is no point.
One likely cause of your problems is that there's no guarantee that a pointer will even fit in a long int. You can check by adding this code:
printf("a regular pointer is %u bytes, long int is %u",
(unsigned int) sizeof structure, (unsigned int) sizeof point);
If the numbers printed are different, that's probably the largest cause of your problems.
If you're using C99, you should #include <stdint.h> and then use the intptr_t type instead of unsigned long to hold a pointer, in any case.
structure is already a pointer, so you don't have to take the address there:
long int point = reinterpret_cast<long int>(structure);
DummyStructure* structure2 = reinterpret_cast<DummyStructure*>(point);
structure is already a pointer. You just want to do point = (long int) structure; (although, realistically, why a long int is involved at all, I don't know. It's a lot easier to just do structure2=structure; which works fine since structure and structure2 are both pointers.)
When you do &structure you're getting the memory location where the pointer itself is stored, which is why it isn't the correct value. You really probably don't want to ever use &structure unless it's being passed into a function which is going to change which DummyStructure structure points to.
Others have answered your question, but I'd like to make a more general comment. You mention JNI; in this case, you don't want long int, but jlong (which will be a typedef to either long int or long long int, depending on the machine. The problem is that long will have a different size, depending on the machine, and will map to a different Java type. Of course, you're counting on the fact that jlong will be big enough to hold a pointer, but since jlong is 64 bits, this seems like a safe bet for the immediate future (and beyond—I don't see a time coming where 64 bits of addressing doesn't suffice).
Also, I would suggest you borrow an idea from Swig, and avoid the subtleties of pointer to integral conversions, by using something like the following:
jlong forJNI = 0;
*reinterpret_cast<DummyStructure*>( &forJNI ) = structure;
// ...
structure2 = *reinterpret_cast<DummyStructure*>( &forJNI );
This is ugly, but it is guaranteed to work (with one caveat) for all
systems where sizeof(DummyStructure*) <= 64.
Just be sure to compile with strict aliasing turned off. (You have to
do this anytime you cast between pointers and ints. IMHO, you shouldn't
have to in cases where the casts are visible to the compiler, but some
compiler writers prefer breaking code intentionally, even when the
intent is clear.)
Long ints aren't the same as pointers. Why don't you just do:
DummyStructure** point;
structure = malloc(sizeof(DummyStructure));
structure->rate = 19;
structure->duration = 92;
point = &structure;
structure2 = *point;
The problem is probably a combination of the fact that 1) you don't dereference point. structure2 is a pointer to structure which is itself a pointer. You'd have to do:
structure2 = *((DummyStructure*)point);
But on top of that is the fact that long ints aren't the same as pointers. There's probably also a signedness issue here.
point = (long int)&structure;
This takes the address of structure which is a DummyStructure* and assign it to point. So point should be a double pointer (pointer to pointer). And when you assign structure2, it should be properly type casted.
typedef struct
{
int rate;
int duration;
} DummyStructure;
DummyStructure* structure;
DummyStructure* structure2;
long int **point;
structure = (DummyStructure*)malloc(sizeof(DummyStructure));
structure->rate = 19;
structure->duration = 92;
point = (long int **)&structure;
structure2 = (DummyStructure*)*point;
If your intention is to make structure2 point to the same memory location as structure, why don't you directly assign it rather than having an intermediate long int **.
The bug is that point is the address of structure, which is itself a pointer to a DummyStructure. In order for structure2 to point to the same thing as structure, you need to dereference point. Ignoring for a second all length, signedness, and similar issues,
structure2 = *(DummyStructure**)point;
would fix your code. But why not just:
structure2 = structure;
If you really want to hold a pointer in something generic, hold it in a void*. At least that's the right size.

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?

Conversion from 'xxxx' to 'yyyy', possible loss of data, suppression?

Sometimes I've got warnings with conversion from a longer type to a smaller type e.g.:
void f( unsigned short i ) // f - accept any numeric type
// smaller than std::vector<>::size_type
{}
std::vector < some_type > v;
..
f ( v.size() );
Usually I was using one of next solutions:
assert( v.size() <= std::numeric_limits< unsigned short >::max() );
f( static_cast< unsigned short >( v.size() ) );
or
f( boost::numeric_cast< unsigned short >( v.size() ) );
But on my present work boost not used and from last month asserts are disallowed.
What other safe ways you know for suppress this warning?
Any pitfalls in discribed ways?
PS:
It is not always possible to change the signature of f, also sometimes really should accept small numeric type.
EDITED:
I want to make conversion as safe as possible.
Why cast in the first place? The vector's size is typically an unsigned integer. If possible, I'd say update the function signature. Warnings are not meant to be suppressed, rather addressed.
The only safe way to deal with this is to ensure that you do not have a loss of conversion at runtime. The assert code will only work during debug builds and will allow for a conversion loss in retail builds. The conversion loss is bad because it will pass around a completely incorrect size for the vector.
What you really need is a mechanism to prevent you from creating data loss. I reccomend using a class like SafeInt. This will prevent a conversion which overflows or underflows by means of throwing an exception.
SafeInt<size_t> size = v.size();
f((unsigned short)size); // Throws if size can't fit in an unsigned short
SafeInt: http://www.codeplex.com/SafeInt
I will now repeat my mantra again: If your code contains casts, there is probably something wrong with the code or the design and you should examine both with a view to removing the cast.
BTW, you upvoted this the last time I posted it!
As size() usually returns an unsigned integer, it should be quite safe to typecast it to a signed one.
f(static_cast<expected-type>(v.size()));
Otherwise change the function signature, if it is possible.