Why does lldb complain my class needs a conversion operator, even though it has one? - lldb

I have a template class with a uint32_t conversion operator
template<uint32_t NumBytes>
struct packed_uint
{
...
inline operator uint32_t() const
{
switch (NumBytes)
{
...
}
}
};
yet when I use the command p (uint32_t)(a_packed_uint) in lldb it says
error: cannot convert 'const a_packed_uint<4>' to 'uint32_t' (aka 'unsigned int') without a conversion operator
I get the same error using static_cast and if I try casting to const uint32_t.
What am I doing wrong?

Related

Is GCC warning on const qualifier correct?

Consider the follow code, which arose from this question:
const int (*foo(const char *a))[1]
{ return (const int (*)[1]) a; }
When compiled with GCC 8.2 (and older versions) using -Wcast-qual, GCC warns:
source>:2:15: warning: cast discards 'const' qualifier from pointer target type [-Wcast-qual]
{ return (const int (*)[1]) a; }
^
Is this warning correct? Clearly the destination type has a const qualifier in it.
It is on the element type rather than on the thing immediately pointed to by the pointer, which is the array type. However, the warning remains even if we use typedef int T[1]; and replace the cast with (const T *). Additionally, per C 2018 6.7.3 10, qualifiers on an array type apply to the element type, not the array type, so the type is the same either way.
Clang does not show this warning.
If we change the cast to (const void *):
const int (*foo(const char *a))[1]
{ return (const void *) a; }
then the warning vanishes. If we add -pedantic to the compilation switches, we get a different warning about const:
source>:2:15: warning: return discards 'const' qualifier from pointer target type [-Wdiscarded-qualifiers]
{ return (const void *) a; }
^~~~~~~~~~~~~~~~
This looks like the same warning except it is about the implied conversion from the return expression to the function return type, whereas the previous warning was about the explicit conversion in the cast. But this one appears only with -pedantic. Why?
This is GCC bug 81631. GCC fails to recognize the cast to a pointer to an array retains the const qualifier, due to complications with qualifiers applied to an array actually applying to the array elements.

Store function address into global variable

Consider the following code:
void f() {};
void* v = f;
int i = f;
int main() { }
Why storing function address into int variable gives me an error:
error: initializer element is not a compile-time constant
But for void* variable doesn't?
Variables declared at file scope ("global") have static storage duration.
All variables with static storage duration must be initialized to a compile-time constant. In C, other variables (not even const ones) don't count as compile-time constants, hence the error.
In addition, you cannot assign a pointer to an integer, doing so is not valid C. You have to manually convert the pointer to an integer type first, by casting it.
In addition, the cast void* v = f; is not well-defined. The C standard only specifies casts between void* and pointer to object type.
Now what you should do to get a function's address is this:
#include <stdint.h>
uintptr_t i = (uintptr_t) f;
int main (void)
{ ...
uintptr_t is guaranteed to be large enough to contain the address of any pointer.
When I compile this, I get:
$ gcc foo.c
foo.c:3:5: warning: incompatible pointer to integer conversion initializing 'int' with an expression of type 'void ()' [-Wint-conversion]
int i = f;
^ ~
foo.c:3:9: error: initializer element is not a compile-time constant
int i = f;
^
1 warning and 1 error generated.
Really, I think that warning ought to be an error. You're trying to put an address into an integer, and that's generally bad form.
That said, if the compiler goes ahead and makes the conversion, the result is not a compile-time constant (because it's a converted value). Thus the error.
Although you're not asking about C++, I was curious as to how the two languages differ, so I checked how my compiler behaved. In that language, both assignments from f are illegal, for good reason. void* is not a pointer to a parameter-less function, and int isn't either.
$ g++ foo.c
clang: warning: treating 'c' input as 'c++' when in C++ mode, this behavior is deprecated
foo.c:2:7: error: cannot initialize a variable of type 'void *' with an lvalue of type 'void ()'
void* v = f;
^ ~
foo.c:3:5: error: cannot initialize a variable of type 'int' with an lvalue of type 'void ()'
int i = f;
^ ~
2 errors generated.
The initializations of both v and i are illegal.
However, some compilers allow conversion from a function pointer to a void* as a compiler extension.
Try compiling with your warnings cranked up (as you should by habit), and you may get warnings on the void* v = f; line as well.
A correct way to store a pointer to the function f would be
void (*p)() = f;
If you really wanted to put the underlying bits of a pointer into an int you could try this:
typedef union _UPTRINT
{
void *ptr;
int i;
} UPTRINT;
Then assign the function pointer to UPTRINT::ptr and access it as i (assuming that pointers and ints are the same size on your platform; adjust the type of i as necessary).

C: a cast warning

I have a code, but have a warning when it was compiling, this was the warning:
1_redis.c: In function \342\200\230main\342\200\231:
1_redis.c:131:23: warning: assignment makes integer from pointer without a cast
[enabled by default]
it says assignment makes integer from pointer without a cast, but cFile and lQueryData are all char* type, why?
#define MAX_LINE_NUM 8000000
#define EACH_THREAD_NUM 10000
long i,posF,posDB;
for (i=0;i<DB_NUM;i++) { lQueryPerDB[i] = 0; }
char *lQueryData = (char *)malloc(DB_NUM*MAX_LINE_NUM*sizeof(char));
lLineCount = lFileLen / lLineLen;
for (i=0;i<lLineCount;i++) {
posF = i * lLineLen;
iDB = get_DB(cFile[posF]);
posDB = iDB * MAX_LINE_NUM + lQueryPerDB[iDB];
lQueryData[posDB] = &cFile[posF]; // this line have warning!!!!
lQueryPerDB[iDB]++;
}
If cFile is a char *, indexing it like cFile[posF] is the same as doing *(cFile + posF), or "give me the value of whatever is posF places from the start of the array." Your address-of operator (&) is unnecessary, and if it weren't, it would probably be the opposite of what you wanted (you want dereference — * — which is automatically done for you with the subscript notation).
As other people have suggested, the correct code is most likely:
lQueryData[posDB] = cFile[posF];
The reason you get the particular warning you do is because using &cFile[posF] gets the address of (i.e., a pointer to) the character in cFile at posF. However, when you then try to assign it to a place in the lQueryData array, it has to first cast that (internally) into a scalar type. A pointer is just a number that indexes into memory, and thus when used for anything but "pointing" to things, it's just an integer. Therefore, what you have is making an integer, from a pointer, without an explicit cast.
You might consider compiling with clang instead of (what I presume is) GCC if you have access to it, it has much more accessible error messages. For instance, the error message for your code above is: warning: incompatible pointer to integer conversion assigning to 'char' with an expression of type 'char *'; remove & (with a little visual pointer to the offending "&" sign).
If they are both char * then why are you using & operator. Just say
lQueryData[posDB] = cFile[posF];
The expression &cFile[posF] is a pointer to the value, so you should be taking its value like this:
lQueryData[posDB] = cFile[posF];

expected ‘uint32_t’ but argument is of type ‘uint32_t *’

I am new in C, trying to call a function, but it gives me error that I can not understand why
int set_price(&colour->type.name);
it returns me expected ‘uint32_t’ but argument is of type ‘uint32_t *’. warning: passing argument ‘int set_price’ makes integer from pointer without a cast
where the pointer is
house_list *colour = NULL;
and
name is defined in struct as
uint32_t name;
the original function accept
int set_price(uint32_t name) { /do something here/ }
what do I do wrong? If in the struct member, name is defined as uint32_t, and I defined a pointer colour, than I believe that I need to use & before colour->type and use dot before name isn't it?
Thank you
set_price(&colour->type.name);
remove the & and you'll be fine
set_price(colour->type.name);
set_price expects an integer as an argument, not a pointer to integer.
I suggest that you should read a good C book.

Why did these variable apparently change type?

Python spoiled me and trying to wrap my mind around C now is being a bloodbath of stupid errors. This is one I can't quite understand.
I wanted the C equivalent of Python's os.path.split, but there's no exact equivalent. strsep looks similar enough, but needs some massaging to be used simply.
First off, I defined my path type: a string of given length.
#define MAX_PATH_LEN 200 /* sigh */
typedef char t_path[MAX_PATH_LEN];
Then I wrote some code that does the actual massaging, attempting to avoid side effects -- just to keep things fool proof.
typedef struct {
t_path next;
t_path remainder;
} t_path_next
t_path_next path_walk_into(t_path path) {
t_path_next output;
t_path my_next, my_remainder = "/";
strncpy(my_next, path, MAX_PATH_LEN);
strsep(&my_next, my_remainder);
output.remainder = my_remainder;
output.next = my_next;
return output;
}
gcc, however, is not impressed.
badp#delta:~/blah$ gcc path.c -Wall
path.c: In function ‘path_walk_into’:
path.c:39: warning: passing argument 1 of ‘strsep’ from incompatible pointer type
/usr/include/string.h:559: note: expected ‘char ** __restrict__’ but argument is of type ‘char (*)[200]’
path.c:41: error: incompatible types when assigning to type ‘t_path’ from type ‘char *’
path.c:42: error: incompatible types when assigning to type ‘t_path’ from type ‘char *’
I am baffled by the note -- how are char ** and char (*)[200] really different -- but the error is even weirder. I want to assign a variable I declared t_path in a field of type t_path, but I don't get to.
Why is that?
For anybody interest here's the correctly working version of the function:
t_path_next path_walk_into(t_path path) {
t_path_next output;
t_path my_path, delim = "/";
char* my_path_ptr = my_path;
strncpy(my_path, path, MAX_PATH_LEN);
strsep(&my_path_ptr, delim); //put a \0 on next slash and advance pointer there.
if (my_path_ptr == NULL) //no more slashes.
output.remainder[0] = 0;
else
strncpy(output.remainder, my_path_ptr, MAX_PATH_LEN);
strncpy(output.next, my_path, MAX_PATH_LEN);
return output;
}
The errors: You can't directly assign to an array, such as a string, in C. You need to copy char by char, or call str(n)cpy, which does it for you.
For the warning : you are probably already aware that array may decay to pointer. That is, for example, what makes an array acceptable as an argument to a function where a pointer is expected. In your case, what you have is a pointer to an array : there is no reason for such a thing to get converted to a pointer to pointer.
For the record, the C99 standard says (6.3.2.1/3) :
Except when it is the operand of the sizeof operator or the unary & operator, or is a
string literal used to initialize an array, an expression that has type ‘‘array of type’’ is
converted to an expression with type ‘‘pointer to type’’ that points to the initial element of
the array object and is not an lvalue.
You're in the context of a unary & : no conversion for you.
For the error : it has already been answered, but array assignment is not directly possible. You might want to use strcpy or strncpy.

Resources