I am writing a program (well... using sample code form Tektronix) to test the message exchange over the network to our spectrum analyser in our lab.
A header file called "decl-32.h" has been provided, and in the sample code is the following line, along with the error it produces:
ibwrt(GpibDevice, "SYSTem:ERRor:ALL?", strlen("SYSTem:ERRor:ALL?"));
"invalid conversion from 'const void*' to 'PVOID {aka void*}' [-fpermissive]"
Within the header file, the following line of code is highlighted as erroneous, along with the following error:
extern int __stdcall ibwrt (int ud, PVOID buf, long cnt);
"initializing argument 2 of 'int ibwrt(int, PVOID, long int)' [-fpermissive]"
The problem is that I am unfamiliar with such complex variable definitions, uses and conversions.
Could somebody be kind enough to offer me some advice? I'm sure this would be relevant to many others who are unfamiliar with such variable types and conversions, etc.
Thank you in advance!
The second parameter to ibwrt is PVOID which is a typedef for void*. In C++, pointer types are implicitly convertible to void*, but, as with all other types, the conversion is not allowed to drop a qulifier. That is, conversion from const char* (which is the type string literals decay to) to void* is illegal. Hence the error.
In C language, which is where the code is coming from, string literals decay to char* and your line will compile as is. The reason is historical - early implementations of C didn't have const keyword.
To fix it, you can cast the const away with a const_cast:
const char* s = "SYSTem:ERRor:ALL?";
ibwrt(GpibDevice, const_cast<char*>(s), strlen("SYSTem:ERRor:ALL?"));
You need to trust the function that it'll not attempt to modify the string literal through the pointer you passed it, otherwise it would invoke undefined behaviour. Seems like a safe assumption in this case (or maybe not, the parameter is named buf, mind you!), but if you want to be sure, do a copy of the string like #MikeSeymour shows in his answer.
The problem is that string literals are immutable, and this function requires a non-const pointer to the data.
If the function is guaranteed not to modify the data, and the lack of const is just an oversight, then you can cast to the required type:
ibwrt(GpibDevice, const_cast<char*>("SYSTem:ERRor:ALL?"), strlen("SYSTem:ERRor:ALL?"));
If it might modify the data, then this will give undefined behaviour, and you'll need a local copy of the string:
const char message[] = "SYSTem:ERRor:ALL?";
ibwrt(GpibDevice, message, strlen(message));
(You could specify the length as the less obvious but perhaps more efficient sizeof message - 1)
Related
I've been trying to write a program in C++ with portaudio, trying to make a simple audio application, something that can record and play audio just to learn. So I have a class, and in the class, I initialize a variable PaStreamParameters inputParameters. Alright so later in the code, I open the stream to record like any other program with Pa_OpenStream,
err = Pa_OpenStream(
&stream,
&inputParameters,
NULL,
sampleRate,
framesPerBuffer,
paNoFlag,
recordCallback,
data);
And I get an error that I'm doing an invalid conversion from int (*)(const void*, const void*, long unsigned int, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*) to an int (*)(const void*, void*, long unsigned int, const PaStreamCallbackTimeInfo*, PaStreamCallbackFlags, void*); note the second parameter, converting from a const void* to a void*. And it makes sense as I am, in fact passing a non const variable, and Pa_OpenStream was written to have a const input. It is even here in the documentation: http://www.portaudio.com/docs/v19-doxydocs/portaudio_8h.html#a443ad16338191af364e3be988014cbbe. So what's the problem? I've seen in multiple places, Pa_OpenStream being passed a non-const parameters. The recording example code, http://portaudio.com/docs/v19-doxydocs/paex__record_8c_source.html, initializes PaStreamParameters inputParameters, outputParameters;, mutates them, and passes it to Pa_OpenStream just like I did. The Ardour source code, in libs/backends/portaudio/portaudio_io.cc, the open_callback_stream function initializes two PaStreamParameters variables, neither being const, and passes them to Pa_OpenStream (in a modified way, checking if it should pass NULL instead).
How do these code work and mine don't? None of them pass const input and output parameters to Pa_OpenStream and they work. How do they not get an invalid conversion from const void* to void*?
audour source code for reference: https://github.com/Ardour/ardour/blob/master/libs/backends/portaudio/portaudio_io.cc
C++ has no problem converting a non-const pointer to a const pointer, the two are perfectly compatible and it will do the conversion automatically. But that's not what the compiler is complaining about here.
It's complaining about the pointer to the callback function, recordCallback. The parameter types declared for a function are part of the type of that function, and they must match exactly or the types are different.
Any Idea how to fix? Would be really useful. I tried changing conformance mode to off and it worked but the other parts of the program failed. Any other fixes?
Line that has problem :
RecursiveDelete(path, L"desktop.ini");
Edit :
The program is to change windows registry files and is connected with my c++ loader. When the project is standalone not connected to the loader it works perfectly fine.
The RecursiveDelete() function takes 2 LPWSTR parameters. LPWSTR is an alias for wchar_t*, ie a pointer to non-const wchar_t data. However, a string literal is const data, in this case L"desktop.ini" is a const wchar_t[12] (including the null terminator), which decays into a const wchar_t* pointer. You can't use a pointer-to-const where a pointer-to-non-const is expected, that is what the error message is complaining about.
IF the function DOES NOT alter the contents of its second parameter, then that parameter should be implemented as a pointer-to-const, eg:
void RecursiveDelete(LPWSTR, LPCWSTR);
(aka void RecursiveDelete(wchar_t*, const wchar_t*);).
If changing the declaration of the function is not an option (ie, it is from an existing API, etc), you could instead cast away the string literal's constness using const_cast (be VERY CAREFUL doing this!), eg:
RecursiveDelete(path, const_cast<LPWSTR>(L"desktop.ini"));
However, making a non-const duplicate of the string literal's data would be much safer, eg:
wchar_t copy[] = L"desktop.ini";
RecursiveDelete(path, copy);
I do have a "C" function
find_register(char *name)
which is called from a "C++" routine. The first tip to call it was
find_register("%ebx")
It results in a warning
deprecated conversion from string constant to 'char*'
OK, I corrected it to
find_register(string("%ebx").c_str())
which results in the error message
"invalid conversion from 'const char*' to 'char*'
Finally,
find_register((char*)string("%ebx").c_str())
is accepted without error message and warnings.
My questions:
1./ The probable reason of the error message is that the possibility of changing a 'const char*' is left open. It is OK, but in the first case the less sophisticated version allows the same, and converting a string constant to 'char *' is a legal, but deprecated conversion. Is there any deeper reason behind?
2./ Is there any simple method to do what I want? (the perfect (for the compiler) code is hardly readable for the programmer)
The reasoning lies in the original roots of C++ language, back in the time when certain amount of backward compatibility with C was considered important.
In C language string literals, despite being non-modifiable, have type char [N]. For this reason they are implicitly convertible to type char * in C. In C++ string literals have type const char[N]. Formally, const char[N] is not implicitly convertible to char *. But for aforementioned C compatibility reasons the original C++ specification (C++98) allowed implicit conversion of string literals to char *. This exception was made for immediate string literals only, as a form of special treatment provided to string literals.
But eventually the matter of C compatibility became unimportant and this special treatment was deprecated in C++03. So, this is what the compiler is telling you. In your find_register("%ebx") call it agrees to convert the immediate string literal to char *, but warns you that this conversion is deprecated. In C++11 this implicit conversion is outlawed entirely.
In all other contexts (not an immediate string literal), implicit conversion of const char [N] or const char * to char * is prohibited and has always been prohibited. This is why your
find_register(string("%ebx").c_str())`
variant has no chance of compiling.
As for working around this restriction... If you are sure that find_register(char *name) does not attempt to change the data pointed by name (and you cannot just change the find_register's parameter type to const char *name), then
find_register(const_cast<char *>("%ebx"))
is a fairly acceptable solution (with an appropriate accompanying comment). Of course, if find_register is a modifying function, then you'll have to do something like
char reg[] = "%ebx";
find_register(reg);
The prototype for the function find_register(char*) indicates that it may change the parameter since it is just a pointer that is passed. You do not mention if you have the source code of that function so I assume you don't otherwise it would be better to change that function to accept a char const * provided it doesn't change the contents.
Otherwise just pass a modifiable array:
char arg[] = "%ebx";
find_register(arg);
to write:
find_register((char*)string("%ebx").c_str())
is dangerous, what if the function does indeed modify the string e.g. strtok? But if you insist at least try to use the C++ style of casting instead of C casting (in this case find_register(const_cast<char*>("%ebx"))).
Side note: personally I find it easier to read to avoid using the C-way of putting const when possible. So instead of writing const char * write char const * and char * const when the pointer is constant i.e. const always goes to the left - it is more consistent.
If you are passing string literals to find_register(char *name), then the function prototype should be find_register(const char *name), as string literals are not modifiable.
With this conversion, C++ will happily let you shoot yourself in the foot and try to modify name, which gives me a segmentation fault, as in the following code:
void modifyIllegally(char* name) {
name[0]='d';
}
int main() {
modifyIllegally("abc");
}
Edit: If you don't control the API of the C program and are sure it won't change the char*, you can disable this warning with compiler flags. For gcc the flag is -Wno-write-strings.
While maintaining old code that uses libmxl2 I get the following error:
error: invalid static_cast
from type ‘const char [8]’
to type ‘xmlChar* {aka unsigned char*}’
in the following piece of code:
xmlNodePtr messageNode = doc->children; // The "Message" node
if(xmlStrcmp(messageNode->name, static_cast<xmlChar*>("Message"))) ... blabla
(same error happens with reinterpret_cast)
Obviously I can resolve with an old style cast (xmlChar*) but what is the proper way of doing this recently in C++?
I use gcc 4.7.2 (and this code was last time compiled 5 years ago :) without this error, but do not ask the version of the old compiler :) )
after some combination of casts this works:
const_cast<xmlChar*>(reinterpret_cast<const xmlChar *>("Message"))
Get a newer version of libxml2. The current version of the API has the following signature:
int xmlStrcmp (const xmlChar * str1,
const xmlChar * str2)
Which is compatible with your const string literal.
As you're stuck with an older version of libxml2 you'll have to const_cast away the constness of the literal and depend on the library not trying to modify the string that you pass it. You'll also need a reinterpret_cast as "regular" chars are usually signed instead of unsigned, e.g.
xmlStrcmp(messageNode->name, reinterpret_cast<xmlChar*>(const_cast<char*>("Message")))
By the way, the reason that you need a reinterpret_cast instead of a plain old static_cast is because you are casting a pointer type to a pointer type pointing at a differently typed object.
As has been stated here a couple of times, you can get the newest version of the lib which is const correct
If that is not an option for any reason, then what you need is a const_cast instead of a static_cast
Your code should look like
if(xmlStrcmp(messageNode->name,
const_cast<xmlChar*>(reinterpret_cast<const xmlChar *>("Message"))))
You can tell this is the case, by looking at the error message
error: invalid static_cast
from type ‘const char [8]’
to type ‘xmlChar* {aka unsigned char*}’
the only difference between the two incompatible types is the const modifier
xmlChar after some research is typedef to unsigned char. Therefore,
A solution is :
// use the implicit conversion to 'char*' to cast away constness:
char* message = "Message";
// explicitly cast to 'unsigned char*'
unsigned char* in = reinterpret_cast<unsigned char*>(message);
xmlChar* test = in;
The removal of constness is usually a bad idea since string literals are not modifiable, but sometimes it is necessary when dealing with legacy libraries that are not const-correct.
The conversion from char* to unsigned char* is safe because all objects can be treated as an array of char, unsigned char, or signed char in C++.
Can someone explain this to me:
char* a;
unsigned char* b;
b = a;
// error: invalid conversion from ‘char*’ to ‘unsigned char*’
b = static_cast<unsigned char*>(a);
// error: invalid static_cast from type ‘char*’ to type ‘unsigned char*’
b = static_cast<unsigned char*>(static_cast<void*>(a));
// everything is fine
What makes the difference between cast 2 and 3? And are there any pitfalls if the approach from 3 is used for other (more complex) types?
[edit]
As some mentioned bad design, etc...
This simple example comes from an image library which gives me the pointer to the image data as char*. Clearly image intensities are always positive so I need to interpret it as unsigned char data.
static_cast<void*> annihilate the purpose of type checking as you say that now it points on "something you don't know the type of". Then the compiler have to trust you and when you say static_cast<unsigned char*> on your new void* then he'll just try to do his job as you ask explicitely.
You'd better use reinterpret_cast<> if you really must use a cast here (as it's obvioulsy showing a design problem here).
Your third approach works because C++ allows a void pointer to be casted to T* via static_cast (and back again) but is more restrictive with other pointer types for safety reasons. char and unsigned char are two distinct types. This calls for a reinterpret_cast.
C++ tries to be a little bit more restrictive to type casting than C, so it doesn't let you convert chars to unsigned chars using static_cast (note that you will lose sign information). However, the type void* is special, as C++ cannot make any assumption for it, and has to rely on the compiler telling it the exact type (hence the third cast works).
As for your second question, of course there are a lot of pitfals on using void*. Usually, you don't have to use it, as the C++ type system, templates, etc. is rich enough to not to have to rely in that "unknown type". Also, if you really need to use it, you have to be very careful with casts to and from void* controlling that types inserted and obtained are really the same (for example, not pointer to subclasses, etc.)
static_cast between pointers works correct only if one of pointers is void or that's casting between objects of classes, where one class is inherited by another.
The difference between 2 and 3 is that in 3, you're explicitly telling the compiler to stop checking you by casting to void*. If the approach from 3 is used for, pretty much anything that isn't a direct primitive integral type, you will invoke undefined behaviour. You may well invoke undefined behaviour in #3 anyway. If it doesn't cast implicitly, it's almost certainly a bad idea unless you really know what's going on, and if you cast a void* back to something that wasn't it's original type, you will get undefined behaviour.
Casts between pointers require reinterpret_cast, with the exception of void*:
Casts from any pointer to to void* are implicit, so you don't need to explicitly cast:
char* pch;
void* p = pch;
Casts from void* to any other pointer only require a static_cast:
unsigned char* pi = static_cast<unsigned char*>(p);
beware, when you cast to void* you lose any type information.
what you are trying to do is incorrect, and false, and error prone and misleading. that's why the compilator returned a compilation error :-)
a simple example
char* pChar = NULL; // you should always initalize your variable when you declare them
unsigned char* pUnsignedChar = NULL; // you should always initalize your variable when you declare them
char aChar = -128;
pChar = &aChar;
pUnsignedChar = static_cast<unsigned char*>(static_cast<void*>(pChar));
then, though pUnsignedChar == pChar nonethless we have *pUnsignedChar == 255 and *pChar == -128.
i do believe this is bad joke, thus bad code.