error: lvalue required as unary & operand - c++

While compiling (with Linux Server release 6.1)
strftime(AppTime, sizeof(AppTime),"%Y/%m/%d %T", localtime(&((long)u32_Time)));
getting error "error: lvalue required as unary '&' operand"
but the same code compiled successfully with Red Hat Enterprise Linux AS release 3.
Why so? How to correct this?

The address-operator & requires a variable to take the address from. The result of your cast (long)u32_Time is a temporary that does not necessarily reside in memory and therefore has no address that could be taken. So if that piece of code ever compiled somewhere it was a nonstandard compiler extension.
The standard, ยง5.3.1,3 demands:
The result of the unary & operator is a pointer to its operand. The operand shall be an lvalue [...]
How to fix this:
std::localtime expects a pointer to a std::time_t so you best provide that. You did not provide any explanation or further code, so I can only guess that u32_Time is some 4 byte unsigned arithmetic type that is supposed to represent a time in some manner. How that is properly converted into a std::time_t depends on how your compiler implements the latter and how you got the value of the further. Simply applying a C-cast is not portable, and casting to long is even less portable.
If, and only if the std::time_t on your current platform is also a unsigned 32 bit type using the same representation as your u32_Time, it might suffice to use
localtime(reinterpret_cast<std::time_t*>(&u32_Time));
More portable would be storing the value in the correct data type first:
std::time_t time = u32_Time;
localtime(&time);
That way you will get the necessary warnings and/or errors if time_t and the type of u32_Time are not compatible.
I would strongly advice against using C-casts, because once you have to port this piece of code to another platform you will have no means to find that nasty cast easily.

It's probably best to start with what the error means. An "lvalue" is something that appears on the left side of an equals sign. What it means is that your argument to the "address of" operator (&) must be something that you could assign to. In your case, this isn't syntactically correct:
(long)u32_Time = 0;
The reason for this restriction is that the & operator returns the address of something that is stored somewhere. (long)u32_Time isn't stored somewhere, but u32_Time is.
This might have worked ok on more tolerant compilers because it would allocate some space for the long representation of u32_Time and then give you a pointer to that, but I wouldn't count on that working (as can be seen in Linux Server release 6.1).
To fix this, you can just create a new variable and take it's address instead:
long long_Time = (long)u32_Time;
strftime(AppTime, sizeof(AppTime),"%Y/%m/%d %T", localtime(&long_Time));
However, that's still not perfect. localtime expects a time_t pointer, not a long pointer, and while they might be the same on your platform, you'd be better off with:
time_t time_t_Time = (time_t)u32_Time;
strftime(AppTime, sizeof(AppTime),"%Y/%m/%d %T", localtime(&time_t_Time));

Related

C++ Why do we need to explicitly cast from one type to another?

I was writing some code recently and found myself doing a lot of c-style casts, such as the following:
Client* client = (Client*)GetWindowLong(hWnd, GWL_USERDATA);
I thought to myself; why do we actually need to do these?
I can somewhat understand why this would be needed in circumstances where there is lot of code where the compiler may not what types can be converted to what, such as when using reflection.
but when casting from a long to a pointer where both types are of the same size, I don't understand why the compiler would not allow us to do this?
when casting from a long to a pointer where both types are of the same size, I don't understand why the compiler would not allow us to do this?
Ironically, this is the place where compiler's intervention is most important!
In vast majority of situations, converting between long and a pointer is a programming error which you don't want to go unnoticed, even if your platform allows it.
For example, when you write this
unsigned long *ptr = getLongPtr();
unsigned long val = ptr; // Probably an error
it is almost a certainty that you are missing an asterisk in front of ptr:
unsigned long val = *ptr; // This is what it should be
Finding errors like this without compiler's help is very hard, hence the compiler wants you to tell it that you know when you are doing on conversions like that.
Moreover, something that is fine on one platform may not work on other platforms. For example, an integral type and a pointer may have the same size on 32-bit platforms, but have different sizes on 64-bit platform. If you want to maintain any degree of portability, the compiler should warn you of the conversion even on the 32-bit platform, where the sizes are identical. Compiler warning will help you identify an error, and switch to a portable pointer-as-integer type intptr_t.
I think the idea is that we want compiler to tell us when we are doing something dodgy and/or potentially unintended. That way we don't do it by accident. So the compiler complains unless we explicitly tell the compiler that this is what we really, really want. We do that by using the a cast.
Edited to add:
It might be better to ask why we are allowed to cast between types. Originally C was created as a strongly typed language. Although it allows promotion/conversion between related object types (like between ints and floats) it is supposed to prevent access and assignment to the wrong type as a language feature, a safety measure. However occasionally this is useful so casting was put in the language to allow us to circumvent the type rules on those occasions when we need to.

Can wrapping a type conversion in a static_cast ever hurt?

I'm updating some old code and I get hundreds of warnings along the lines of warning C4244: '+=': conversion from 'std::streamsize' to 'unsigned long', possible loss of data in Visual Studio.
The project compiles and runs fine when just ignoring the warnings, but I want to remove them and put a static_cast<unsigned long>() function around each. Considering the code runs fine now, could this potentially be harmful?
Yes, static_cast can hurt, as it will tell the compiler to shut up, as you know what you are doing. The question is whether you actually know what you are doing?
Obviously, casting to a smaller type can result in an unexpected result if the stored data exceeds the smaller types size. Use a static_cast if you know for sure, that this case won't ever happen or that you expect a truncated value. If not, keep the warning until you have properly designed your code.
The project compiles and runs fine when just ignoring the warnings
To start with, never ignore warnings. Think over what your code actually does instead.
Considering the code runs fine now, could this potentially be harmful?
Regarding your particular case, a static_cast<unsigned long> from std::streamsize will be harmful.
As the reference documentation of std::streamsize says, it's intentionally a signed type:
The type std::streamsize is a signed integral type used to represent the number of characters transferred in an I/O operation or the size of an I/O buffer. It is used as a signed counterpart of std::size_t, similar to the POSIX type ssize_t.
Static casting in that case actually means loss of semantics.
The idea is that conversions allowed by static_cast are somewhat less
likely to lead to errors than those that require reinterpret_cast. In
principle, it is possible to use the result of a static_cast without
casting it back to its original type, whereas you should always cast
the result of a reinterpret_cast back to its original type before
using it to ensure portability.
from Bjarne Stroustrup's C++ Style and Technique FAQ
Be careful with consts. static_cast doesn't cast away const.
In general, I think it would be better to rewrite your code instead of "casting every problem away" in hope that everything goes well.

Conversion to enumeration type requires an explicit cast (static_cast, C-style cast or function-style cast)

I need to work on a project that was written in msvcpp6.0sp6
I DIDN'T write the project. I know very little about its inner works. I DO know it WAS POSSIBLE to build it in the past.
while trying to build this project that was built successfuly in the past(not by me)
I get the error:
Conversion to enumeration type requires an explicit cast (static_cast, C-style cast or function-style cast)
for example:
error C2664: 'strncpy' : cannot convert parameter 2 from 'const unsigned short *' to 'const char *'
error C2664: 'void __cdecl CString::Format(const unsigned short *,...)' : cannot convert parameter 1
for a few dozen implicit conversions. I mustn't change the code. how can I force the complier to accept the implicit convertions?
I mustn't change the code. how can I force the complier to accept the
implicit convertions?
Quite likely you need to get the same compiler that was used for the code in the first place, and use that.
If my guess (in a comment on unwind's answer) is correct about that unsigned short* error then it's simply not possible to compile this code in Unicode mode, because the source is insufficiently portable. Suppressing the error for the conversion, even if it's possible via some compiler setting, will just result in code that compiles but doesn't work.
I'd expect that also to imply that the old dll probably isn't compatible with the rest of your current code, but if you've been using it up to now then either I'm wrong about the reason, or else you've got away with it somehow.
That sounds crazy.
The use of unsigned short * with string-handling functions like strncpy() initially seems to make no sense at all. On second thought though, it makes me wonder if there is some kind of "wide character" configuration that is failing. If strncpy() was "re-targeted" by the compiler to work on 16-bit characters, having it expect unsigned short * makes sense and would explain why the code passes it such. At least "kind of" explain, it's still odd.
You can't. There are no such implicit conversions defined by the C++ language.
Visual C++ 6.0 was a law unto itself; by implementing something that merely looked a bit like the C++ language, it may have accepted this invalid code.
C++ is a typesafe language. But it allows you to tell the compiler to "shut up" by the evil known as casting.
Casting from integers to enums is often a necessary "evil" cast, for example, you cannot loop through enums where you have, say, a restricted number of values for which you have given enumerations. Therefore you have to use an integer and cast them to enums for this purpose.
Sometimes you do need to cast data structors to const char * rather than const void * just so you can perform pointer arithmetic. However for the purpose of strcpy, it is difficult to see why you want to cast in unsigned shorts. If these are wide characters (and the old compiler did not know of wchar_t) then it may be "safe" to cast it to const wchar_t * and use it in a wide-string copy. You could also use C++ strings, i.e. std::string and std::wstring.
If you really do not wish to update the source code for ISO compliance then your best bet is to use the original VC++ 6.0 compiler for your legacy code. Not least because even though you know this code to work, if it were compiled with a different compiler it will be different code and may no longer work. Any undefined or implementation defined compiler behaviour either exploited or used inadvertently could cause problems if a different compiler is used.
If you have an MSDN subscription, you can download all previous versions of VC++ for this purpose.

static_cast wchar_t* to int* or short* - why is it illegal?

In both Microsoft VC2005 and g++ compilers, the following results in an error:
On win32 VC2005: sizeof(wchar_t) is 2
wchar_t *foo = 0;
static_cast<unsigned short *>(foo);
Results in
error C2440: 'static_cast' : cannot convert from 'wchar_t *' to 'unsigned short *' ...
On Mac OS X or Linux g++: sizeof(wchar_t) is 4
wchar_t *foo = 0;
static_cast<unsigned int *>(foo);
Results in
error: invalid static_cast from type 'wchar_t*' to type 'unsigned int*'
Of course, I can always use reinterpret_cast. However, I would like to understand why it is deemed illegal by the compiler to static_cast to the appropriate integer type. I'm sure there is a good reason...
You cannot cast between unrelated pointer types. The size of the type pointed to is irrelevant. Consider the case where the types have different alignment requirements, allowing a cast like this could generate illegal code on some processesors. It is also possible for pointers to different types to have differrent sizes. This could result in the pointer you obtain being invalid and or pointing at an entirely different location. Reinterpret_cast is one of the escape hatches you hacve if you know for your program compiler arch and os you can get away with it.
As with char, the signedness of wchar_t is not defined by the standard. Put this together with the possibility of non-2's complement integers, and for for a wchar_t value c,
*reinterpret_cast<unsigned short *>(&c)
may not equal:
static_cast<unsigned short>(c)
In the second case, on implementations where wchar_t is a sign+magnitude or 1's complement type, any negative value of c is converted to unsigned using modulo 2^N, which changes the bits. In the former case the bit pattern is picked up and used as-is (if it works at all).
Now, if the results are different, then there's no realistic way for the implementation to provide a static_cast between the pointer types. What could it do, set a flag on the unsigned short* pointer, saying "by the way, when you load from this, you have to also do a sign conversion", and then check this flag on all unsigned short loads?
That's why it's not, in general, safe to cast between pointers to distinct integer types, and I believe this unsafety is why there is no conversion via static_cast between them.
If the type you're casting to happens to be the so-called "underlying type" of wchar_t, then the resulting code would almost certainly be OK for the implementation, but would not be portable. So the standard doesn't offer a special case allowing you a static_cast just for that type, presumably because it would conceal errors in portable code. If you know reinterpret_cast is safe, then you can just use it. Admittedly, it would be nice to have a straightforward way of asserting at compile time that it is safe, but as far as the standard is concerned you should design around it, since the implementation is not required even to dereference a reinterpret_casted pointer without crashing.
By spec using of static_cast restricted by narrowable types, eg: std::ostream& to std::ofstream&. In fact wchar_t is just extension but widely used.
Your case (if you really need it) should be fixed by reinterpret_cast
By the way MSVC++ has an option - either treat wchar_t as macro (short) or as stand-alone datatype.
Pointers are not magic "no limitations, anything goes" tools.
They are, by the language specification actually very constrained. They do not allow you to bypass the type system or the rest of the C++ language, which is what you're trying to do.
You are trying to tell the compiler to "pretend that the wchar_t you stored at this address earlier is actually an int. Now read it."
That does not make sense. The object stored at that address is a wchar_t, and nothing else. You are working in a statically typed language, which means that every object has one, and juts one, type.
If you're willing to wander into implementation-defined behavior-land, you can use a reinterpret_cast to tell the compiler to just pretend it's ok, and interpret the result as it sees fit. But then the result is not specified by the standard, but by the implementation.
Without that cast, the operation is meaningless. A wchar_t is not an int or a short.

How to cast from bool to void*?

I'm trying to build cairomm for gtkmm on windows using mingw. Compilation breaks at a function call which has a parameter which does a reinterpret_cast of a bool to a void*.
cairo_font_face_set_user_data(cobj(), &USER_DATA_KEY_DEFAULT_TEXT_TO_GLYPHS, reinterpret_cast<void*>(true), NULL);
This is where the code breaks, and reason is "invalid reinterpret_cast from bool to void*". Why is this happening, and how can I modify this line to get it to compile? Need help
I see this is user data and you have control over what is done with the value, cast the bool to an int first: reinterpret_cast<void *> (static_cast<int> (true)). Doing this makes sense in that the void* parameter takes the place of template functions in this ANSI-C library. All you need is a true/false value. So, there should be no danger in temporarily encoding this as a pointer as long as it is well documented as such. Really, you would be better off with this: reinterpret_cast<void *> (1) or reinterpret_cast<void *> (+true).
It looks like it should work, according to the standard. Section 3.9.1-7 says bool is an integral type, and 5.2.10-5 says a value of integral type can be explicitly converted to a pointer using reinterpret_cast. It appears that your compiler is not fully standard.
Could you get away with changing the "true" to a 1? Converting between integers and pointer types is an old and dishonorable tradition in C and hence C++, and it would be surprising to find a compiler that wouldn't do it.
Or, if you really really have to do this, try (void *)true. Then wash your hands.
The only compiler I have that complains about this is GCC (MinGW with GCC 3.4.5) - and I'm not sure why. The standard seems to clearly indicate this is permitted:
3.9.1 Fundamental types
...
Types bool, char, wchar_t, and the
signed and unsigned integer types are
collectively called integral types.
5.2.10 Reinterpret cast:
...
A value of integral type or
enumeration type can be explicitly
converted to a pointer.
That said, monjardin's workaround of using reinterpret_cast<void *> (static_cast<int> (true)) or reinterpret_cast<void *> (1) are reasonable workarounds.
reinterpret_cast is a bad idea. Tell us more about the problem you're trying to solve, and perhaps we'll find a solution without resorting to reinterpret. Why do you want to convert bool to void*?
In some situations, it is highly desirable to have the compiler warn or error on code like reinterpret_cast<void*>(true), even though this code is apparently legal C++. For example, it aids in porting to 64-bit platforms.
Casting a 64-bit pointer into an integral type that is smaller than a pointer (such as int or bool) is often a bug: you're truncating the pointer's value. Furthermore, the C++ specification doesn't seem to guarantee that you can directly cast a pointer into a smaller integral type (emphasis added):
5.2.10.4. A pointer can be explicitly converted to any integral type large enough to hold it. The mapping function is implementation-defined.
Likewise, casting a smaller integral type into a 64-bit pointer (as with reinterpret_cast<void*>(true)) is often a bug as well: the compiler has to fill in the pointer's upper bits with something; does it zero-fill or sign-extend? Unless you're writing low-level platform-specific code for memory mapped I/O access or DMA, you usually don't want to be doing this at all, unless you're doing something hacky (like stuffing a Boolean into a pointer). But the C++ specification doesn't seem to say much about this case other than that it is implementation-defined (footnote omitted):
5.2.10.5. A value of integral type or enumeration type can be explicitly converted to a pointer.*
A pointer converted to an integer of sufficient size (if any such exists on the implementation) and back to the same pointer type will have its original value; mappings between pointers and integers are otherwise implementation-defined.
#monjardin suggested reinterpret_cast<void*>(static_cast<int>(true)). If the origin of the error was the mismatch between the integral type's size and the pointer size, then this will work on most 32-bit platforms (where both int and void* are 32 bits) but fail on most 64-bit platforms (where int is 32 bits and void* is 64 bits). In that case, replacing int in this expression with a pointer-sized integer type such as uintptr_t or DWORD_PTR (on Windows) should work, since conversions between bool and pointer-sized integers are allowed, and so are conversions between pointer-sized integers and pointers.
Later versions of GCC have the following warning suppression options, but not for C++:
-Wno-int-to-pointer-cast (C and Objective-C only)
Suppress warnings from casts to pointer type of an integer of a different size.
-Wno-pointer-to-int-cast (C and Objective-C only)
Suppress warnings from casts from a pointer to an integer type of a different size.
It fails because the cast makes no sense - you are taking a boolean true/false value, and asking the compilre to interpret this as a pointer, which in blunt terms is a memory location. The two arent even remotely related.
Try a newer version of your compiler. I just tested and this cast works on at least gcc 4.1 and above. I don't know exactly how gcc versions map to mingw versions though.