Passing a pointer of the wrong type

May 9, 2020 at 2:12pm
Hi, I'm using some code that I found in an article by Vikash Agarwal on writing an ODBC driver.

I'm attempting to build a skeleton using this code (my background is in SQL but no experience with C++), and after a few days of fizzing around the net and using the fab tutorial on this site, I've been able to understand some of it.

But on compile I get an error on the last line shown below. The code E0167 says it all: argument of type "UCHAR *" is incompatible with parameter of type "Const char *"

So far so understandable; it seems function strlen expects a const pointer arg, but the pointer I'm using is the wrong type. If I peek at the def for UCHAR I see: typedef unsigned char UCHAR; And there is also a warning that says "Conversion from integral type to pointer type requires reinterpret_cast, C-style cast, or function-style cast." How good is that, it even tells me what to do.

Now, in SQL I might cast a value from one type to another with a light heart, but pointers are a whole new ballgame for me.

I have 3 questions. If someone could assist that would be super:
i) Can I safely recast from UCHAR * to const char *?
ii) If so, how?
iii) What should I be looking for in future, to determine whether I can do this safely in other circumstances? In other words, I guess what I am saying is, what does the error really mean?

Thanks heaps,

Jack


1
2
3
4
5
6
7
8
9
10
RETCODE SQL_API SQLDriverConnect(
    HDBC             hDBC, HWND     hWnd,
    UCHAR* ptrConnStrIn, SWORD   lenConnStrIn,
    UCHAR* ptrConnStrOut, SWORD   lenConnStrOut,
    SWORD* pcbConnStrOut, UWORD    uwMode)
{
    OutputDebugString("SQLDriverConnect called\n"); // for DBMON

    if (lenConnStrIn == SQL_NTS && ptrConnStrIn) // get in-string length
        lenConnStrIn = strlen(ptrConnStrIn);
May 9, 2020 at 2:21pm
It depends on the value of the uchar if it is safe to cast to a char
If the value is > 127 you will lose some information.
The GSL have a narrow cast. It will throw an exception if it is not safe
https://github.com/gsl-lite/gsl-lite, if you don't have a choice you can use static_cast or gsl::narrow_cast
May 9, 2020 at 2:29pm
Thanks Thomas! 20 past midnight here, and now you've got me thinking again, I was just about to call it a night.

So I thought this was a pointer, and that it would therefore be very likely to be much larger than 127? Like, all the time?



May 9, 2020 at 2:39pm
Are you sure that you need it?
Doesn't lenConnStrIn specify the length of ptrConnStrIn?

BTW: if it is so late why don't you look at it with a fresh mind tomorrow?
Last edited on May 9, 2020 at 2:40pm
May 10, 2020 at 7:16am
In short, fresh mind and all, I think I do need it because, as far as I can see, that is what the code is trying to do. That is, find the length of the input string.

What about the 3rd argument
UCHAR* ptrConnStrIn,

I assume from the format of the argument that this is a pointer, am I correct? If I peek at the definition of strlen I see
1
2
3
4
_Check_return_
size_t __cdecl strlen(
    _In_z_ char const* _Str
    );


So that makes sense: strlen wants a pointer, and I pass it the pointer, and it should return the length (up to \0). But it wants a const pointer, and I only have what I think is called a volatile pointer.

Can I cast a volatile pointer to a const pointer?

May 10, 2020 at 2:28pm
You need to cast an unsigned char* to char* - at least in C++. I am not sure in C
Does your code has sth. to do with this:
https://docs.microsoft.com/en-us/sql/odbc/reference/syntax/sqldriverconnect-function?view=sql-server-ver15
May 10, 2020 at 10:42pm
Yes, my code has everything to do with that Microsoft SQLDriverConnect, I am trying to compile the skeleton for the ODBC driver.

What is the best way to cast an unsigned char* to char*? The reinterpret cast allows me to compile, but will it work at run time? Or should I use C-style or function cast?
reinterpret_cast<char*>(ptrConnStrIn)

Also, for the information of beginners like myself, the mistakes I have been making are:
1) parameters are passed by value, so that the purpose of the const is to ensure that you can pass values to a function that are not alterable by the function.
2) because of 1), the pointer that is being passed 'ptrConnStrIn' is const by default i.e. strlen only gets a copy
3) the definition of the strlen argument in <string.h> is _In_z_ char const* _Str. That does not mean that it expects a pointer constant, which would be unnecessary since it only gets a copy of the pointer anyway. It means that the value pointed to by the pointer is constant and cannot be changed by the function.
4) I changed the original code so that parameter names were not eg 'szConnStrIn', but 'ptrConnStrIn'. I did that because it appeared 'szConnStrIn' should contain a numeric value for a size. But the sz prefix is widely used in C++ to indicate that it is a null terminated string.
5) If you are a lit graduate like me, be careful, C++ people love metonymy and can confound you by talking about a string and then writing down a pointer. For more information about metonymy and The Container For The Thing Contained, go here: https://www.newyorker.com/magazine/1942/03/21/here-lies-miss-groby
Topic archived. No new replies allowed.