C: a cast warning - c

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];

Related

How to take address of mpz_t passed as parameter in C code?

I have C code that wants to do something like this:
#include <gmp.h>
extern void g(mpz_t in);
extern mpz_t temp; /* initialized elsewhere */
void f(mpz_t in, int flag) {
mpz_t *arg;
if (flag) {
mpz_mul_ui(temp, in, 2);
arg = &temp;
} else {
/* this bit is the problem */
arg = &in;
}
/* placeholder for more complex code using *arg (readonly) */
g(*arg);
}
The purpose here is to avoid a lot of duplicated code represented here by g(*arg) – I want it to act either on the original input or on a modified version of it.
But while arg = &temp compiles fine, arg = &in does not. I understand that this is because mpz_t is typedef'd as an array (typedef __mpz_struct mpz_t[1]), and from Error when attempting to use a type from GNU's GMP library as the yylval type for Bison I get the additional clue "the array decays to a pointer when used as a function argument", but it isn't clear to me what the actual type of that pointer is so that I can do the right thing here. I've tried arg = &in, arg = in, arg = &in[0], and, in each case, GCC just tells me "warning: initialization from incompatible pointer type".
My system GCC (7.5.0) sadly does not report what the incompatible types are but, trying again with a later version (11.2.0) does tell me warning: assignment to '__mpz_struct (*)[1]' from incompatible pointer type '__mpz_struct **', which is great. But I can't guess from that if there's an invocation that will allow the assignment safely without a cast, or if a cast is required what I should be casting – should it be arg = (mpz_t *)&in? Is there a way to do this without casts?
Your overall assessments of the problems are about right:
Because the mpz_t type is defined as an array (even though it has only one element), arguments of that type will decay to pointers (to the first – and only – element).
Also, because it is an array type, you cannot make direct assignments to objects of that type (so you couldn't just remove the * from the declaration of arg, for example).
What you can do, though, is to declare the local arg variable as a pointer to the underlying type of the array – that is the __mpz_struct type. So, you would have: __mpz_struct* arg;.
With this, you must then remove the address-of (&) operator from the right-hand side of the two arg assignments in your function: the temp array will (when used in such an expression) automatically 'decay' into a pointer; and the in argument has already decayed thusly.
Here's an outline:
#include <gmp.h>
extern void g(mpz_t in);
extern mpz_t temp; /* initialized elsewhere */
void f(mpz_t in, int flag) {
__mpz_struct* arg; // Pointer to the underlying type of an "mpz_t" array
if (flag) {
mpz_mul_ui(temp, in, 2);
arg = temp; // RHS decays into a __mpz_struct* pointer
}
else {
/* problem solved: */
arg = in; // RHS is already a __mpz_struct* pointer
}
/* placeholder for more complex code using arg (readonly) */
g(arg); // Note that the "*" needs to be gone, here!
}
Note also that, in the above code, there is no cast used!
Notes on the use of the mpz_t* arg; (pointer-to-array) type and casts.
In terms of its actual value, the address of an array is the same as the address of its first element. However, a pointer to an array is not the same type as a pointer to its first element. We can use two methods to convert one to the other: a cast, or an "address of"/indirection operator (depending on the direction of the conversion).
Further, in almost all expressions, the use of an array identifier (without a suffixed [...]) will be converted to a pointer to its first element. Thus, in the expression, x = temp (using the temp from the original code), the RHS will decay to a pointer to temp[0]. As this is the same address as that of the array itself, we can (safely) cast this to an mpz_t* type in an assignment to arg:
arg = (mpz_t*)temp;
But we can avoid a cast, here. One place where an array does not decay into a pointer is when it is the operand of the & (address of) operator (the other is when used as a sizeof operand). Thus, the expression, &temp will yield a type of mpz_t* that will be the address of the array:
if (flag) {
mpz_mul_ui(temp, in, 2);
arg = &temp; // RHS yields a `mpz_t*` type
}
In the case of the other assignment (i.e., when the given in argument is the RHS), the situation is rather different and we must here use a cast. This is because that argument has already been converted to a pointer (its type is __mpz_struct*, as indicated in my suggested code, above). Also, any attempt to take its address will almost certainly yield an inappropriate/incorrect value – it will be the address of the passed argument (a pointer), likely on the stack.
So, as the value of the in argument is the address of the first element of the source array (used in the call to our function), we can cast that to an mpz_t* type and it can then be used as the address of that source array:
else {
arg = (mpz_t*)in; // "in" has correct value but wrong type, so cast
}
So, if you really want to use the mpz_t* type for your local arg variable, you can. But I would caution against using pointers to arrays wherever possible: they are prone to cause unexpected issues, later on, especially when you start using pointer arithmetic or indexing operations.

Pointers in C : assigning a literal to int *

What is really happening here when we provide a definition like below?
int * a = 2;
What is really happening behind the scenes?
SOLVED
Here a will point to memory address 2.
The result of conversion from integer to a pointer is implementation-defined in C, quoting C99 Section 6.3.2.3:
5 An integer may be converted to any pointer type. Except as previously specified, the result is implementation-defined, might not be correctly aligned, might not point to an entity of the referenced type, and might be a trap representation.
So you shouldn't rely on such conversion except when the literal is 0 which will give you a null pointer.
In practice you are likely to find that the pointer will hold the memory address specified by the integer constant:
#include <stdio.h>
int main(void) {
int * a = 2;
printf("%p", a); /* prints 0x2 in gcc */
return 0;
}
Most compilers will also warn about this unsafe cast :
$ gcc test.c test.c: In function ‘main’: test.c:4:13: warning:
initialization makes pointer from integer without a cast [enabled by
default] int * a = 2;
^
In here the memory for "a" will not be allocated. So, it gives the segmentation fault error.
It will try to take the 2 as a address and pointer a will try to point the address 2. But it may be our system does not have that address or it may be allocated for some other process.
So, in the compiling time it will give the one warning message.
Warning: initialization makes pointer from integer without a cast [enabled by default]

Dubious syntax to access array content

In some legacy code I have to maintain, & operators are put in front of arrays names whenever the arrays are to be passed as (void *) arguments
Here is a simple example :
char val = 42;
char tab[10];
memcpy(&tab, &val, 1);
It compiles with gcc or clang without errors or warnings. It also gives the expected result.
Is this syntax legal ?
Why does this works ?
Notes : I usually use one of the following syntax :
memcpy(tab, &val, 1);
memcpy(&tab[0], &val, 1);
Epilog :
As an additional test, I used a function taking a (char*) argument instead of (void*)
I get the following warning if I try to compile with clang :
warning: incompatible pointer types passing 'char (*)[10]' to parameter of type 'char *' [-Wincompatible-pointer-types]
Edit 1 :
In the original example tab was given with a size of 1 element
I just changed the size to 10 for the sake of generality.
Edit 2 :
As mentionned in the answers, memcpy takes (void*) and not (char*)
memcpy's parameters are of type void*, not char*. Any argument of pointer type (excluding function pointers) is implicitly converted to void*. This is a special-case rule that applies only to void*.
Given the declaration
char tab[1];
either tab or &tab is valid as an argument to memcpy. They evaluate to pointers of different types (char* and char (*)[1]), but both pointing to the same memory location; converting either to void* yields the same value.
For a function that actually requires a char* argument, only tab is valid; &tab is of the wrong type. (For a variadic function like printf or scanf, the compiler may not be able to detect the type mismatch.)

What does this c code row do? (const VAR = "string";)

Stumbled on this row of c code but was unsure if it is valid or not. What does it do? What type will the variable have?
const VARNAME = "String of text";
Curiously, I wasn't expecting this to compile, but it does. However, compiler doesn't like it too much:
..\main.c:4:7: warning: type defaults to 'int' in declaration of 'VARNAME'
..\main.c:4:17: warning: initialization makes integer from pointer without a cast
So it does take int as default type, and thus VARNAME has a pointer value, since a string is a pointer (which later could be cast as char*).
This works perfectly (on a Intel IA32 machine):
#include<stdio.h>
const VARNAME = "String of text";
int main()
{
printf("%s\n", (char*)VARNAME);
return 0;
}
But I personally wouldn't use such implicit typing. As explained on the comments below:
it's even dangerous since sizeof(int) might be smaller than
sizeof(char*)
What GCC tries to do is:
Make a constant VARNAME with the default type, that is int;
make this constant int contain a pointer to the character constant.
On my machine, it doesn't compile, probably because int is 32 bits and pointers are 64 bits wide.
a.c:1: error: initializer element is not computable at load time
Find the definition of "VARNAME" and you will see. I would say something like "char*".

Warning: pointer of type 'void *' used in subtraction

Although it runs correctly, the following results in the aforementioned compiler warning:
return ((item - (my->items))/(my->itemSize));
'item' is a 'void *'; 'my->items' is a 'void *'; 'my->itemSize' is an 'int'
Casting 'item' and 'my->items' as an 'int *' caused the program to run improperly. What is the best way to remove the warning?
Additions and subtractions with pointers work with the size of the pointed type:
int* foo = 0x1000;
foo++;
// foo is now 0x1004 because sizeof(int) is 4
Semantically speaking, the size of void should be zero, since it doesn't represent anything. For this reason, pointer arithmetic on void pointers should be illegal.
However, for several reasons, sizeof(void) returns 1, and arithmetic works as if it was a char pointer. Since it's semantically incorrect, you do, however, get a warning.
To suppress the warning, use char pointers.
Cast to a char *:
return ((char *)item - (char *)my->items)/my->itemSize);
Since char is size of 1 byte, you will get the value you are expecting vs your int * pointer example which calculates how many ints are between the two address. That's how pointer arithmetic works.
The problem is that you are doing aritmethical operations in a pointer, I wonder how is that running properly.
If you're trying to do normal arithmetic, you have to dereference the pointer (e.g. *item). If you're trying to do pointer arithmetic, the pointer has to be of a type, like char* or int* (otherwise the compiler won't know how much to increment by).

Resources