I am having one of those "discards qualifiers" cases that I cannot figure out. I have code that empirically functions until I try to get rid of the warning. Here's the error:
filter.c:28:21: warning: passing 'const filterentry [1]' to parameter of type
'struct filter_matchbuffer *' discards qualifiers
[-Wincompatible-pointer-types-discards-qualifiers]
filterServiceBuffer(filterinparsermap);
^~~~~~~~~~~~~~~~~
In the code below, I have a series of text string filters that are text that is paired with a function. For instance, when I see the "$GPRIP" string, it copies the message. Anyway, there's whole series of these pairs in filterinparsermap[].
#define FILTER_COPY 3
enum
{
FILTERFUNCTION_COPY = FILTER_COPY,
#define FILTERFUNCTION_COPY FILTERFUNCTION_COPY
};
struct filter_matchbuffer
{
int indexofstring;
int filterbehavior;
const char *const strforcomparison;
};
typedef struct filter_matchbuffer filterentry;
#define FILTERTEXTENTRY(num, behavior, x) \
{ \
num, behavior, #x \
}
const filterentry filterinparsermap[] = {
FILTERTEXTENTRY(1, FILTER_COPY, "$GPRIP")};
void filterServiceBuffer(struct filter_matchbuffer p_filtermap[])
{
}
int main(){
filterServiceBuffer(filterinparsermap);
return(0);
}
I would really like to get rid of the error, but I just cannot seem to get my struct and pointer types to agree and still have the code compile. Any suggestions would be greatly appreciated.
to get rid of the error ("discards qualifiers" )
Edit function signature to accept a pointer to const data.
// void filterServiceBuffer(struct filter_matchbuffer p_filtermap[])
void filterServiceBuffer(const struct filter_matchbuffer p_filtermap[])
Related
I am working on using a structure in a function, but when I try to run the code I get this error:
note: expected 'pixels_t' {aka 'struct '} but argument is of type 'pixels_t *' {aka 'struct *'}
Here is my code:
typedef struct{
unsigned int a, b, c;
}letters_t;
void fillLetterArray(letters_t letters);
int main (void){
letters_t letterArray[100];
fillLetterArray(letterArray);
}
void fillLetterArray(letters_t letters){
}
Thank you in advance for the answer.
Your function takes structure, but your main program wants to pass pointer to the structure. You need to change this function accordingly:
void fillLetterArray(letters_t *letters);
int main (void)
{
letters_t letterArray[100];
fillLetterArray(letterArray);
}
void fillLetterArray(letters_t *letters)
{
}
I suggest you abstain from (ab)using typedef without a good reason, it's meant to create abstractions, and there's no advantage in this context.
If the intention is to fill an array, as the name implies, then the function fillLetterArray needs to take a pointer to the array; additionally, it's a good idea to include the length of the array in a parameter:
#include <stdint.h> // for size_t
struct letters {
unsigned int a, b, c;
};
static void fillLetterArray(struct letters *letters, size_t length);
int main (void) {
struct letters_t letterArray[100];
fillLetterArray(letterArray, 100);
}
void fillLetterArray(struct letters *letters, size_t length) {
...
}
I'm new to C and currently exploring the concept of function overloading via the use of _Generic in C11.
In this SO post, #Lundin provides the following code snippet, which I've gotten running with no issues:
#include <stdio.h>
void func_int (int x) { printf("%d\n", x); }
void func_char (char ch) { printf("%c\n", ch); }
#define func(param) \
_Generic((param), \
int: func_int(param), \
char: func_char(param)); \
int main()
{
func(1);
func((char){'A'});
}
#Lundin also mentioned the following:
A much better way would be to make a function interface with a single
struct parameter, which can be adapted to contain all the necessary
parameters. With such an interface you can use the above simple method
based on _Generic. Type safe and maintainable.
So I decided to extend the above example to structs to see it in action.
Below is my attempt:
#include <stdlib.h>
#include <stdio.h>
typedef struct args_int Args_int;
typedef struct args_char Args_char;
void func_int(Args_int args);
void func_char(Args_char args);
struct args_int {
int val;
};
struct args_char {
char val;
};
#define func(param)\
_Generic((param),\
Args_int: func_int(param),\
Args_char: func_char(param));
void func_int (Args_int args) {
printf("%d\n", args.val);
}
void func_char (Args_char args) {
printf("%c\n", args.val);
}
int main(void) {
Args_char args = {0};
args.val = 'A';
func(args);
}
However, unfortunately, I get the following compilation error, which complains that I've passed in an Args_char when the compiler is expecting an Args_int. Clearly, my intent is to pass an Args_char and my expectation is for func_char to be called as a result.
struct_args_by_val_executable.c:35:10: error: passing 'Args_char' (aka 'struct args_char') to parameter of incompatible type 'Args_int' (aka 'struct args_int')
func(args);
^~~~
struct_args_by_val_executable.c:20:28: note: expanded from macro 'func'
Args_int: func_int(param),\
^~~~~
struct_args_by_val_executable.c:24:25: note: passing argument to parameter 'args' here
void func_int (Args_int args) {
^
1 error generated.
Why isn't my example working as expected and what is the fix here?
On a related note, I managed to get a "pointer to a struct" version working without any issues as shown below. However, given the above compilation error, I feel as though this may have been a fluke?
#include <stdio.h>
typedef struct args_int Args_int;
typedef struct args_char Args_char;
void func_int(Args_int *args);
void func_char(Args_char *args);
struct args_int {
int val;
};
struct args_char {
char val;
};
#define func(param)\
_Generic((param),\
Args_int*: func_int(param),\
Args_char*: func_char(param));
void func_int (Args_int *args) {
printf("%d\n", args->val);
}
void func_char (Args_char *args) {
printf("%c\n", args->val);
}
int main(void) {
Args_char args = {0};
args.val = 'A';
func(&args);
}
The output to the above is as expected:
A
The problem is that all expressions used in _Generic must be valid.
In your example macro func expands to:
int main(void) {
Args_char args = {0};
args.val = 'A';
_Generic(args,
Args_int: func_int(args),
Args_char: func_char(args));
}
Note that using func_int(args) for args which is Args_char is causing an error.
The solution to that is using _Generic to select a function pointer, next apply arguments to it.
#define func(param) \
_Generic((param), \
Args_int: func_int, \
Args_char: func_char) (param)
Just posting this "for the record":
That's actually not a very good code example of me that you've found there! It's much better to include the parameter list outside the _Generic clause just as #tstanisl just mentioned in their answer (I'd accept that one as the answer to your question). That's how the C committee intended the feature to be used even, you can find such examples in the standard itself, see for example 6.5.1:
#define cbrt(X) _Generic((X), \
long double: cbrtl, \
default: cbrt, \
float: cbrtf \
)(X)
The code snippet you found works by luck since char and int can be converted to each other when calling a function "as if by assignment". When using two non-compatible types that cannot get implicitly converted, the macro would expand incorrectly for the wrong type.
I've now updated https://stackoverflow.com/a/44633838/584518 to use this:
#define func(param) \
_Generic((param), \
int: func_int, \
char: func_char)(param) \
Here is a MRE
#include <string.h>
typedef char* mytype;
typedef int(*cmp)(const mytype, const mytype);
void foo(cmp f) {}
int main(void) {
foo(strcmp);
}
When I compile I get:
$ gcc mre.c -Wall -Wextra
mre.c: In function ‘foo’:
mre.c:7:14: warning: unused parameter ‘f’ [-Wunused-parameter]
7 | void foo(cmp f) {}
| ~~~~^
mre.c: In function ‘main’:
mre.c:10:9: warning: passing argument 1 of ‘foo’ from incompatible pointer type [-Wincompatible-pointer-types]
10 | foo(strcmp);
| ^~~~~~
| |
| int (*)(const char *, const char *)
mre.c:7:14: note: expected ‘cmp’ {aka ‘int (*)(char * const, char * const)’} but argument is of type ‘int (*)(const char *, const char *)’
7 | void foo(cmp f) {}
| ~~~~^
The first warning is irrelevant. But what do I do about the second? I tried changing the typedef to:
typedef int(*cmp)(mytype const,mytype const);
But that gave the exact same result. When I changed to:
typedef int(*cmp)(const char*, const char*);
it worked, but that's not preferable for obvious reasons. Another thing that worked but also is not preferable is this:
typedef const char* mytype;
typedef int(*cmp)(mytype, mytype);
So what have I missed here?
The problem I'm trying to solve is that I want to create a generic structure where the data is of type mytype. The user of the structure is expected to implement a compare function, but I want it to work with strcmp in case mytype is of type char*.
Note that mytype not necessarily needs to be a pointer. It depends on what data type the user specifies. Also, I know that typedefing pointers is bad practice in general, but I consider this a special case because I want to typedef whatever the type is, and it may be a pointer.
The structure looks like this:
struct node {
struct node *next;
mytype data;
};
I managed to solve it with #define mytype char* but that feels very ugly, and I would prefer if there was another way. I want it to be portable, so I don't want to use gcc extensions.
typedef char* mytype;
mytype is a pointer to char. const mytype is a const pointer to char not pointer to const char.
Unfortunately in C you cant use typedef pointers and the use this type to declare pointer to const object.
you need to
typedef int(*cmp)(const char *, const char *);
void foo(cmp f) {}
int main(void) {
foo(strcmp);
}
or
foo((cmp)strcmp);
BTW it a very bad practice to hide pointers behind the typedefs.
This question already has answers here:
Incompatible pointer types passing in _Generic macro
(2 answers)
Closed 6 years ago.
Recently I answered some question asking how to implement complex const correctness of a structure member. Doing this I used Generic expressions and encountered strange behavior. Here is the sample code:
struct A
{
union {
char *m_ptrChar;
const char *m_cptrChar;
} ;
};
#define ptrChar_m(a) _Generic(a, struct A *: a->m_ptrChar, \
const struct A *: a->m_cptrChar, \
struct A: a.m_ptrChar, \
const struct A: a.m_cptrChar)
void f(const struct A *ptrA)
{
ptrChar_m(ptrA) = 'A'; // NOT DESIRED!!
}
On GCC and Clang the generic expression select the case when the type of a must be struct A which doesn't make any sense. When I comment the last two cases though it's working fine. Why is this - is it some bug?
The exact error messages on clang are:
test.c:17:5: error: member reference type 'const struct A *' is a pointer; did you mean to use '->'?
ptrChar_m(ptrA) = 'A'; // NOT DESIRED!!
^
test.c:12:45: note: expanded from macro 'ptrChar_m'
struct A: a.m_ptrCHar, \
^
test.c:17:5: error: member reference type 'const struct A *' is a pointer; did you mean to use '->'?
ptrChar_m(ptrA) = 'A'; // NOT DESIRED!!
^
test.c:13:51: note: expanded from macro 'ptrChar_m'
const struct A: a.m_cptrChar)
^
test.c:17:21: error: cannot assign to variable 'ptrA' with const-qualified type 'const struct A *'
ptrChar_m(ptrA) = 'A'; // NOT DESIRED!!
^
test.c:15:24: note: variable 'ptrA' declared const here
void f(const struct A *ptrA)
^
test.c:23:18: error: invalid application of 'sizeof' to a function type [-Werror,-Wpointer-arith]
return sizeof(main);
4 errors generated.
Although the non-matching selections are not evaluated, the compiler is still compiling the code. So using the . operator on a pointer to a structure is not allowed.
If your input expression is always a variable, you could take the address of the variable representing the structure instance.
#define AptrChar_m(a) _Generic(a, struct A *: a->m_ptrChar, \
const struct A *: a->m_cptrChar)
#define ptrChar_m(a) AptrChar_m(_Generic(a, struct A *: a, \
const struct A *: a, \
struct A: &a, \
const struct A: &a))
I have the following code, which I read and read many times and it always appears to be okay, but the compiler says:
error: incompatible types when assigning to type 'struct Type[10]'
from type 'Type'
This is the code:
#include <stdio.h>
typedef struct
{
int a;
int b;
} Type;
typedef struct
{
Type (*typeArray)[10];
} Type2;
void someFunction(Type2 *type2Variable, Type (*typeArray)[10])
{
Type typeNewValue;
type2Variable->typeArray[0] = typeNewValue; /* This throws the error */
}
int main(int argc, char **argv)
{
Type typeArray[10];
Type2 type2Variable;
someFunction(&type2Variable, &typeArray);
}
I'm sure the solution is just a * somewhere but I can't find it.
Update
Thanks a lot for your answers, this was just a non-sense example to show my problem (this isn't the real code).
The solution was:
(*type2Variable->typeArray)[0] = typeNewValue;
Instead of:
type2Variable->typeArray[0] = typeNewValue;
Type (*typeArray)[10] declares a pointer to an array of size 10 of the type Type. It seems that you want do declare a array of Type:
typedef struct
{
Type typeArray[10];
} Type2;
void someFunction(Type2 *type2Variable, Type * typeArray) { /* ... */ }
You are trying to assign a single Type where a Type[10] is expected, and that is exactly what the compiler is complaining about. You would have to change the Type2::typeArray member from Type (*typeArray)[10]; to Type typeArray[10]; for that assignment to work.
The names you are choosing for arguments are helping to confuse things.
The way your code is written, your error on the line indicated
type2Variable->typeArray[0] = typeNewValue; /* This throws the error */
is because it should be written:
type2Variable->typeArray = typeArray; /* to match argument name */
Look at the argument here:
// V-------V
void someFunction(Type2 *type2Variable, Type (*typeArray)[10])
{
Type typeNewValue, *pTypeNewValue;
pTypeNewValue = &typeNewValue;
type2Variable->typeArray = typeArray; //No longer throws error
}
change to
void someFunction(Type2 *type2Variable, Type (*typeArray)[10])
{
Type typeNewValue;//uninitialized
type2Variable->typeArray = typeArray;//maybe :) But for what.
(*type2Variable->typeArray)[0] = typeNewValue;
}