How to correctly cast time_t to long int? - c++

I'm still learning about type casting in C++ and I'm currently doing this
long int t = time(NULL);
I'm using VS2013 and noticed the conversion from 'time_t' to 'long' warning so I thought I would type cast it to look like;
long int t = static_cast<long int> time(NULL);
However this doesn't work yet combining a static cast and a C-style cast works
long int t = static_cast<long int> (time(NULL));
I was just wondering if anyone could help shed some light on this?

time(NULL) is not a cast but a function call which returns time_t. Since time_t is not exactly the same type as long int, you see the warning.
Furthermore, static_cast<T>(value) requires the parenthesis, that is why your first version does not work.

Your question contains the answer. The static_cast generic method in the code you provide takes the time_t type as its input and converts it to a long int as its return value. This code does not contain a C-style type-cast.
long int t = static_cast<long int> (time(NULL));
Type-casting should also work too, because time_t is an arithmetic type and the C cast operator will perform the promotion to the long int type.
long int t = (long int)time(NULL);
This casting tutorial might be an interesting read for you.

A time_t value is the number of seconds since the start of Jan 1 1970. Casting that to 32-bit long you therefore restrict yourself to values representing time values before the year 2038, roughly. That's not a good idea, and the ungoodness of it is the reason for your warning.
The attempted expression
static_cast<long int> time(NULL)
is just invalid syntax. A static_cast requires a parenthesis with the value.

Related

how does the short(vector.size()) command conversion work in C++?

I don't know any other way to return the size of a vector other than the .size() command, and it works very well, but, it return a variable of type long long unsigned int, and this in very cases are very good, but I'm sure my program will never have a vector so big that it need all that size of return, short int is more than enough.
I know, for today's computers those few enused bytes are irrelevant, but I don't like to leave these "loose ends" even if they are small, and whem I was programming, I came across some details that bothered me.
Look at these examples:
for(short int X = 0 ; X < Vector.size() ; X++){
}
compiling this, I receive this warning:
warning: comparison of integer expressions of different signedness: 'short int' and 'std::vector<unsigned char>::size_type' {aka 'long long unsigned int'} [-Wsign-compare]|
this is because the .size() return value type is different from the short int I'm compiling, "X" is a short int, and Vector.size() return a long long unsigned int, was expected, so if I do this:
for(size_t X = 0 ; X < Vector.size() ; X++){
}
the problem is gone, but by doing this, I'm creating a long long unsigned int in variable size_t and I'm returning another variable long long unsigned int, so, my computer allocale two variables long long unsigned int, so, what I do for returning a simple short int? I don't need anything more than this, long long unsigned int is overkill, so I did this:
for(short int X = 0 ; X < short(Vector.size()) ; X++){
}
but... how is this working? short int X = 0 is allocating a short int, nothing new, but what about short (Vector.size()), is the computer allocating a long unsigned int and converting it to a short int? or is the compiler "changing" the return of the .size() function by making it naturally return a short int and, in this case, not allocating a long long unsined int? because I know the compilers are responsible for optimizing the code too, is there any "problem" or "detail" when using this method? since I rarely see anyone using this, what exactly is this short() doing in memory allocation? where can i read more about it?
(thanks to everyone who responded)
Forget for a moment that this involves a for loop; that's important for the underlying code, but it's a distraction from what's going on with the conversion.
short X = Vector.size();
That line calls Vector.size(), which returns a value of type std::size_t. std::size_t is an unsigned type, large enough to hold the size of any object. So it could be unsigned long, or it could be unsigned long long. In any event, it's definitely not short. So the compiler has to convert that value to short, and that's what it does.
Most compilers these days don't trust you to understand what this actually does, so they warn you. (Yes, I'm rather opinionated about compilers that nag; that doesn't change the analysis here). So if you want to see that warning (i.e., you don't turn it off), you'll see it. If you want to write code that doesn't generate that warning, then you have to change the code to say "yes, I know, and I really mean it". You do that with a cast:
short X = short(Vector.size());
The cast tells the compiler to call Vector.size() and convert the resulting value to short. The code then assigns the result of that conversion to X. So, more briefly, in this case it tells the compiler that you want it to do exactly what it would have done without the cast. The difference is that because you wrote a cast, the compiler won't warn you that you might not know what you're doing.
Some folks prefer to write that cast is with a static_cast:
short X = static_cast<short>(Vector.size());
That does the same thing: it tells the compiler to do the conversion to short and, again, the compiler won't warn you that you did it.
In the original for loop, a different conversion occurs:
X < Vector.size()
That bit of code calls Vector.size(), which still returns an unsigned type. In order to compare that value with X, the two sides of the < have to have the same type, and the rules for this kind of expression require that X gets promoted to std::size_t, i.e., that the value of X gets treated as an unsigned type. That's okay as long as the value isn't negative. If it's negative, the conversion to the unsigned type is okay, but it will produce results that probably aren't what was intended. Since we know that X is not negative here, the code works perfectly well.
But we're still in the territory of compiler nags: since X is signed, the compiler warns you that promoting it to an unsigned type might do something that you don't expect. Again, you know that that won't happen, but the compiler doesn't trust you. So you have to insist that you know what you're doing, and again, you do that with a cast:
X < short(Vector.size())
Just like before, that cast converts the result of calling Vector.size() to short. Now both sides of the < are the same type, so the < operation doesn't require a conversion from a signed to an unsigned type, so the compiler has nothing to complain about. There is still a conversion, because the rules say that values of type short get promoted to int in this expression, but don't worry about that for now.
Another possibility is to use an unsigned type for that loop index:
for (unsigned short X = 0; X < Vector.size(); ++X)
But the compiler might still insist on warning you that not all values of type std::size_t can fit in an unsigned short. So, again, you might need a cast. Or change the type of the index to match what the compiler think you need:
for (std::size_t X = 0; X < Vector.size(); ++X_
If I were to go this route, I would use unsigned int and if the compiler insisted on telling me that I don't know what I'm doing I'd yell at the compiler (which usually isn't helpful) and then I'd turn off that warning. There's really no point in using short here, because the loop index will always be converted to int (or unsigned int) wherever it's used. It will probably be in a register, so there is no space actually saved by storing it as a short.
Even better, as recommended in other answers, is to use a range-base for loop, which avoids managing that index:
for (auto& value: Vector) ...
In all cases, X has a storage duration of automatic, and the result of Vector.size() does not outlive the full expression where it is created.
I don't need anything more than this, long long unsigned int is overkill
Typically, automatic duration variables are "allocated" either on the stack, or as registers. In either case, there is no performance benefit to decreasing the allocation size, and there can be a performance penalty in narrowing and then widening values.
In the very common case where you are using X solely to index into Vector, you should strongly consider using a different kind of for:
for (auto & value : Vector) {
// replace Vector[X] with value in your loop body
}

Why does implicit conversion of int to long long int give unexpected answer in C++?

I read that conversion from int to long long int is promotion and hence thought that there shouldn't be any issue as there is no loss of data, unlike the vice versa conversion.
But when I multiply two ints of large value and store it in long long int, it is showing me negative number.
Eg:
int a=1000000, b=1000000;
long long int c=a*b;
cout<<c;
The above code gives me a negative value. Can someone explain why?
a*b is still of type int. Once it's evaluated, the result is then converted to long long int. At that point it's too late to avoid overflow. Convert one of your values to long long int before preforming the multiplication. Try this :
#include <iostream>
int main()
{
int a = 1000000, b = 1000000;
long long int c = static_cast<long long int>(a)*b;
std::cout << c;
return 0;
};
The multiplication is happening as an int, which overflows, giving Undefined Behaviour (in this case overflow, which is very normal - your combination of compiler+settings may even guarantee it), and after that the result is being converted to long long.
I think you want to do the conversion on one of the arguments before multiplication, so that the multiplication is performed using long longs:
long long c = static_cast<long long>(a)*b;
In this way, b will be promoted to long long before the multiplication takes place, and the whole operation will be performed safely, and with the desired result.
Because multiplying two ints will result in another int that comes with all the overflow problems attached. This int is then (after the fact) promoted to a long long int which still means it's not what you want.
Promote at least one of the operands to have the other promoted and get the result you want.

long long value in Visual Studio

We know that -2*4^31 + 1 = -9.223.372.036.854.775.807, the lowest value you can store in long long, as being said here: What range of values can integer types store in C++.
So I have this operation:
#include <iostream>
unsigned long long pow(unsigned a, unsigned b) {
unsigned long long p = 1;
for (unsigned i = 0; i < b; i++)
p *= a;
return p;
}
int main()
{
long long nr = -pow(4, 31) + 5 -pow(4,31);
std::cout << nr << std::endl;
}
Why does it show -9.223.372.036.854.775.808 instead of -9.223.372.036.854.775.803? I'm using Visual Studio 2015.
This is a really nasty little problem which has three(!) causes.
Firstly there is a problem that floating point arithmetic is approximate. If the compiler picks a pow function returning float or double, then 4**31 is so large that 5 is less than 1ULP (unit of least precision), so adding it will do nothing (in other words, 4.0**31+5 == 4.0**31). Multiplying by -2 can be done without loss, and the result can be stored in a long long without loss as the wrong answer: -9.223.372.036.854.775.808.
Secondly, a standard header may include other standard headers, but is not required to. Evidently, Visual Studio's version of <iostream> includes <math.h> (which declares pow in the global namespace), but Code::Blocks' version doesn't.
Thirdly, the OP's pow function is not selected because he passes arguments 4, and 31, which are both of type int, and the declared function has arguments of type unsigned. Since C++11, there are lots of overloads (or a function template) of std::pow. These all return float or double (unless one of the arguments is of type long double - which doesn't apply here).
Thus an overload of std::pow will be a better match ... with a double return values, and we get floating point rounding.
Moral of the story: Don't write functions with the same name as standard library functions, unless you really know what you are doing!
Visual Studio has defined pow(double, int), which only requires a conversion of one argument, whereas your pow(unsigned, unsigned) requires conversion of both arguments unless you use pow(4U, 31U). Overloading resolution in C++ is based on the inputs - not the result type.
The lowest long long value can be obtained through numeric_limits. For long long it is:
auto lowest_ll = std::numeric_limits<long long>::lowest();
which results in:
-9223372036854775808
The pow() function that gets called is not yours hence the observed results. Change the name of the function.
The only possible explaination for the -9.223.372.036.854.775.808 result is the use of the pow function from the standard library returning a double value. In that case, the 5 will be below the precision of the double computation, and the result will be exactly -263 and converted to a long long will give 0x8000000000000000 or -9.223.372.036.854.775.808.
If you use you function returning an unsigned long long, you get a warning saying that you apply unary minus to an unsigned type and still get an ULL. So the whole operation should be executed as unsigned long long and should give without overflow 0x8000000000000005 as unsigned value. When you cast it to a signed value, the result is undefined, but all compilers I know simply use the signed integer with same representation which is -9.223.372.036.854.775.803.
But it would be simple to make the computation as signed long long without any warning by just using:
long long nr = -1 * pow(4, 31) + 5 - pow(4,31);
As a addition, you have neither undefined cast nor overflow here so the result is perfectly defined per standard provided unsigned long long is at least 64 bits.
Your first call to pow is using the C standard library's function, which operates on floating points. Try giving your pow function a unique name:
unsigned long long my_pow(unsigned a, unsigned b) {
unsigned long long p = 1;
for (unsigned i = 0; i < b; i++)
p *= a;
return p;
}
int main()
{
long long nr = -my_pow(4, 31) + 5 - my_pow(4, 31);
std::cout << nr << std::endl;
}
This code reports an error: "unary minus operator applied to unsigned type, result still unsigned". So, essentially, your original code called a floating point function, negated the value, applied some integer arithmetic to it, for which it did not have enough precision to give the answer you were looking for (at 19 digits of presicion!). To get the answer you're looking for, change the signature to:
long long my_pow(unsigned a, unsigned b);
This worked for me in MSVC++ 2013. As stated in other answers, you're getting the floating-point pow because your function expects unsigned, and receives signed integer constants. Adding U to your integers invokes your version of pow.

assigning a value to a long long integers using gcc on sparc solaris

I came across something that I think rather strange. The test program
int main(int argc, char* argv[])
{
cout<<"hello"<<endl;
long unsigned l = 0x12345678;
long long unsigned ll = 0x12345678;
cout<<sizeof(l)<<endl;
cout<<sizeof(ll)<<endl;
};
output is:
hello
4
8
No surprises there. The long int has a size of 4 bytes and the long long has a size of 8 bytes.
However, when I change it so that the long long is assigned
long long unsigned ll = 0x123456789;
at compile time I get
error: integer constant is too large for "long" type
Now this same test does compile if I force a 64 bit build using the option -m64. Am I doing something wrong or is this a bug in GCC?
Change that to
long long unsigned ll = 0x123456789ULL; // notice the suffix
Without the suffix, the literal is bigger than the maximum unsigned long value on your machine, and that, according to C++03 (but not C++11, which has long long), is undefined behavior. This means that anything can happen, including a compile-time error.
It's also worth nothing that there's no long long in C++03, so it's not guaranteed to work, you're relying on an extension. You'd probably better be off using C++11 instead.
The thing here is that many people seem to look at a line of code like your:
unsigned long long ll = 0x123456789; /* ANTI-PATTERN! Don't do this! */
and reason "oh, the type is unsigned long long, so the value is unsigned long long and it gets assigned", but that's just not how C works. Literals have their own type, that doesn't depend on the context in which they're being used. And the type of integer literals is int.
This is the same fallacy as when folks do:
const double one_third = 1 / 3; /* ANTI-PATTERN! Don't do this! */
Thinking "the type on the left is double, so this should assign 0.3333333...". That's just (again!) not how C works. The types of the literals being divided is still int, so the right hand side evaluates to exactly 0, which is then converted to double and stored in the one_third variable.
For some reason, this behavior is deeply non-intuitive to many people, which is why there are many variants of the same question.

How to get rid of the warning with time.h in C++?

When I use this
#include<time.h>
//...
int n = time(0);
//...
I get a warning about converting time to int. Is there a way to remove this warning?
Yes, change n to be a time_t. If you look at the signature in time.h on most / all systems, you'll see that that's what it returns.
#include<time.h>
//...
time_t n = time(0);
//...
Note that Arak is right: using a 32 bit int is a problem, at a minimum, due to the 2038 bug. However, you should consider that any sort of arithmetic on an integer n (rather than a time_t) only increases the probability that your code will trip over that bug early.
PS: In case I didn't make it clear in the original answer, the best response to a compiler warning is almost always to address the situation that you're being warned about. For example, forcing higher precision data into a lower precision variable loses information - the compiler is trying to warn you that you might have just created a landmine bug that someone won't trip over until much later.
Time returns time_t and not integer. Use that type preferably because it may be larger than int.
If you really need int, then typecast it explicitly, for example:
int n = (int)time(0);
I think you are using Visual C++. The return type of time(0) is 64bit int even if you are programming for 32bit platform unlike g++. To remove the warning, just assign time(0) to 64bit variable.
You probably want to use a type of time_t instead of an int.
See the example at http://en.wikipedia.org/wiki/Time_t.
The reason is time() functions returns a time_t time so you might need to do a static cast to an int or uint in this case. Write in this way:
time_t timer;
int n = static_cast<int> (time(&timer)); // this will give you current time as an integer and it is same as time(NULL)