Pregunta

While I debug my minor porting program, I have question about type casting differences.

Here is my source (below) :

  1 #include <time.h>
  2 #include <stdio.h>
  3 
  7 int main () {
  8     clock_t now; //unsigned long 
  9     struct tm * mac_time; // const long
 10     char *time_str;
 11     now = time (NULL);
 12     mac_time = localtime((const long *)&now); 
 13                           // localtime ( const long <- unsigned long)
 13     time_str = asctime(mac_time);
 14     printf("Now : %s\n",time_str);
 15     return 0;
 16 }

First, it works properly, there's no error right now. But I have a question about type casting difference.

In line 12, since type casting warning has occurred, I changed the value's type for debug.

but what is the difference between

12     mac_time = localtime((const long *)&now);

and

12     mac_time = localtime(&(const long *)now);

I thought there's no difference to each other, because this is only different from 'casted value's address and 'value's address casted'.

But complier throws out warning message latter one.

Will you give me some advice for this type casting issue?

¿Fue útil?

Solución 2

For the case

mac_time = localtime((const long *)&now);  

you are casting &now, which is of pointer to clock_t type, to const long *, i.e, pointer to const long type. No problem if localtime expecting argument of type pointer to const long type. While in second case

 mac_time = localtime(&(const long *)now);  

now is of clock_t and you are casting it to const long * and then trying to pass its address to the function and the compiler is showing you error.
Now about the error:

error: cannot take the address of an rvalue of type 'const long *' mac_time = localtime(&(const long *)now); 

You should note that casting produce an r-value. On the other hand & require an l-value as an operand. That's why you can't do &(const long *)now and compiler is throwing the error.

And finally note that there is no call by reference in C instead all calls are by value.

Otros consejos

(const long *)&now takes the address of now and interprets it as an address of a const long.

&(const long *)now interprets now as an address of a const long and takes the address of that address. This is dangerous, because you are basically converting an integer or float to a pointer without any justification as to why the memory location identified by now is accessible to your application.

The pointer cast is completely unnecessary. If your program appears to work, it's an unlucky coincidence. (I say "unlucky" because it means the error is not being diagnosed.)

localtime() takes an argument of type const time_t*, not clock_t*. time_t and clock_t are distinct types, used for different purposes, even though they might happen to be defined in the same way in some particular implementation.

Change the definition of now to:

time_t now;

and call localtime like this:

mac_time = localtime(&now);

Any cast, especially a pointer cast, should be viewed with suspicion. Casts are too often used to silence compiler warnings, when the real solution is to fix your code so things are declared with the correct type in the first place.

As for the question you're asking -- well, it doesn't matter much, since the code is fundamentally incorrect. This:

mac_time = localtime((const long *)&now)

takes the address of now (which, in your code, is of type clock_t*) and converts it to const long*. Since localtime expects an argument of type const time_t*, and apparently time_t is defined as long on your implementation, this appears to work.

This:

mac_time = localtime(&(const long *)now);

takes the value of now (which at this point has not been initialized) and converts it to a const long*; in other words, it takes a garbage numeric value and converts it to a pointer. It then attempts to take the address of that pointer -- but since it's a pointer value, not a pointer object, it has no address. The above is a compile-time error. (I'd expect your compiler to treat this as a fatal error, not just a warning.)

But forget all that. Just declare your objects to be of the correct types in the first place, and you won't have to worry about casts.

(There are cases where casts, even pointer casts, are necessary and appropriate, but not for what you're trying to do here.)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top