I was wondering if it makes sense to cast the result of sizeof?
Example:
Change sizeof(example) to (size_t) sizeof(example)
The return type is std::size_tbut I get the error "Invalid arguements" in many functions (malloc, memset, ...) and after the cast it works. A quick check with printf showed me, that the results stayed the same.
-edited-
As requested a short example function:
__cxa_dependent_exception* __cxxabiv1:: __cxa_allocate_dependent_exception() throw()
{
__cxa_dependent_exception *ps_ret;
ps_ret = static_cast<__cxa_dependent_exception *> (o_exception_pool.allocate (
(size_t) sizeof(__cxa_dependent_exception )));
if (!ps_ret)
{
std::terminate ();
}
memset (ps_ret, 0, (size_t) sizeof(__cxa_dependent_exception ));
return ps_ret;
}
Without the casts this code throws the mentioned error. The full example can be found in the gcc 4.5.4 source code "libstdc++-v3/libsupc++/eh_alloc.cc"
I am using MinGW.
Yes, you can cast result of sizeof, since sizeof(something) is compile time and you will get result in type of (size_t)5 if sizeof(something) returns 5.
Your question condenses to "can you cast std::size_t to another type".
Of course you can, subject to the normal type casting rules. For example, casting this to an int could get you in hot water for a very large type on a system with a 16 bit int. In other words, check that the new type has adequate capacity.
Extra brownie points if you can do that at compile time in C++.
Related
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.]
I am trying to understand some legacy code using AfxBeginThread.
To my understanding LPVOID is defined as a pointer to a void object. I have this function:
Start(LPVOID pParam){
...
int iTemp = (int)pParam;
...
}
And then the call:
int ch1 = 1;
AfxBeginThread(Start(), (LPVOID)ch1);
I am getting the following compiler warning when compiling for 64bit:
warning C4312: 'type cast': conversion from 'int' to 'LPVOID' of greater size
I am
not 100% sure this is a proper use of a pointer
to avoid the warning, I could use a helper function like (LPVOID) PtrToInt(ch1), but that doesn't look right to me as well
Could anyone help me understand the mechanics behind this? I've been trying to find an example online which uses AfxBeginThread in a similar fashion but failed so far.
MS states:
The parameter is a single value. The value the function receives in this parameter is the value that was passed to the constructor when the thread object was created. The controlling function can interpret this value in any manner it chooses. It can be treated as a scalar value or a pointer to a structure containing multiple parameters, or it can be ignored.
This warning occurs because you are compiling on a 64 bit machine where sizeof(void*) is 8 bytes but sizeof(int) is 4.
A proper way to handle this would be to use an integer type for ch1 which is the same size as a void pointer. This is the exact use case for intptr_t.
And so, it should be safe if you use ìntptr_t to hold the ch1 variable. See also this question: C++: Is it safe to cast pointer to int and later back to pointer again?
not 100% sure this is a proper use of a pointer
You have the right hunch. No, it is not proper use of a pointer.
You can pass a pointer to the function.
int ch1 = 1;
int* ptr = &ch1;
AfxBeginThread(Start(), ptr);
Getting the following warning:
ttgload.c(1654): warning C4312: 'type cast': conversion from 'FT_UInt' to 'void *' of greater size
Which seems rather odd.
The line of code in question is this:
if ( FT_List_Find( &loader->composites,
(void*)(unsigned long)glyph_index ) )
and glyph_index is declared FT_UInt.
FT_UInt is typedef unsigned int so it is rather strange to convert an int to a void*.
Any ideas on how to deal with this warning?
FT_UInt is typedef unsigned int so it is rather strange to convert an int to a void*.
Actually it's not. It's perfectly fine and allowed to convert between integers and pointers. A particular application of this is "user parameters" to a function where you register integer or a pointer together with a function callback.
However the two-fold typecast (void*)(unsigned long) is a recipe for getting problems. It's not guaranteed that sizeof(unsigned ling) >= sizeof(void*) which may cause all kinds of problems (i.e. undefined behaviour) of pointers get truncated.
The proper types to use when someone wants an integer that also can hold a pointer are uintptr_t and intptr_t.
Any ideas on how to deal with this warning?
In this particular case it's likely not a cause of problems, because that pointer is going to be cast back to an FT_UInt. In the long run it would make sense to file an issue and change the prototype of FT_List_Find to accept a uintptr_t instead of a pointer; unfortunately this would also break a lot of existing programs.
So I was looking through some boost source code and came across this:
(from <boost/checked_delete.hpp>)
template<class T> inline void checked_delete(T * x)
{
// intentionally complex - simplification causes regressions
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
}
Anyone happen to know why it is implemented in this way? Wouldn't sizeof(T) (for example) already be enough?
Someone asked the same question earlier. This post written by Peter Dimov (one of the writers of boost/checked_delete.hpp) pretty much speaks for itself:
What's the result of applying sizeof to an incomplete type?
A compile-time error, unless the compiler chooses to return 0 as a
nonstandard extension.
Why is sizeof called twice?
The second sizeof is a workaround for a Metrowerks CodeWarrior bug in
which the first typeof is never instantiated unless used.
Why is the result of sizeof cast to void? What exactly does that
line
do?
Silences a compiler warning.
This is just a guess; but there may be compilers out there that just emit a warning when you write sizeof(incomplete_type) and return 0. So you're making sure the array declaration fails in that case by trying to declare an array of size -1.
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.