Removal of warnings when I compile - c

This is a sample piece of code I am posting below. I am getting a warning when I compile this program as shown below:
samp2.c: In function `main':
samp2.c:37: warning: passing arg 1 of `my_func' from incompatible pointer type
The code is shown below:
typedef enum TES_status_e
{
TES_stat_unknown,
TES_stat_ok,
TES_stat_too_high,
TES_stat_too_low,
TES_stat_short_GND,
TES_stat_connected,
TES_stat_not_connected
} TES_status_t;
typedef enum DIAG_status_e
{
DIAG_stat_unknown,
DIAG_stat_ok,
DIAG_stat_too_high = 10,
DIAG_stat_too_low,
DIAG_stat_short_GND,
DIAG_stat_connected,
DIAG_stat_not_connected
} DIAG_status_t;
typedef int (*MyPtr)(TES_status_t);
int my_func(MyPtr);
int test(DIAG_status_t);
main()
{
my_func(&test);
}
int my_func(MyPtr Val)
{
Val(DIAG_stat_too_high);
}
int test(DIAG_status_t c)
{
printf("The val of c is %d\n",c);
}
This is the warning shown as below
samp2.c: In function `main':
samp2.c:37: warning: passing arg 1 of `my_func' from incompatible pointer type
Please let me know how to remove this warning.

You declared my_func to take a function that accepts a TES_status_t enum as argument however the actual test function takes a DIAG_status_t argument that is why you get a warning.
Also the function takes a function pointer, but a function name like test is in fact a function pointer so you only need to supply the function name, not the address:
my_func((MyPtr)test);

Wait, the warning looks like it's right to me.
Despite what you may think, TES_status_t is not equivalent to DIAG_status_t.
I recommend that you fix your code, not the warning.

GCC is right.
You define MyPtr as a pointer to a function that takes a TES_status_t argument and then supply a pointer to a function that takes a DIAG_status_t argument.
EDIT:
You can suppress the warning by explicitly casting to MyPtr: my_func((MyPtr)test);
However this is usually a recipe for disaster, because you essentially introduce non-obvious dependencies between types and the code that uses them.
True, enumerations in C are represented by an int type and in this case both enumerations seem to have a correspondence to each other. But what happens in two weeks when you decide to e.g. add a new state in DIAG_status_t? Your program will break subtly and you will have a hard time tracking the problem because you will have ignored what little type checking the compiler does for you.

my_func expects a pointer to a function taking TES_status_t value and returning an int.
You're calling it with a pointer to a function taking a DIAG_status_t and returning an int.

Edit the line 37 of your samp2.c file till you get no more warnings. Don't turn compiler warnings off, they are very useful. If using gcc, ask for (almost) all of them with -Wall.
A TES_status_t value is not a DIAG_status_t value (but don't think that casting TES_stat_too_high to a DIAG_status_t will give you DIAG_stat_too_high)

Related

Explanation behind value returned by int x=printf

I was randomly experimenting with code and tried to assign printf to an integer variable, using different compilers. Different values were returned. What is the explanation for that?
#include <stdio.h>
int main ()
{
int x;
x = printf;
printf ("%d", x);
return 0;
}
Value returned on my compiler is 4195360.
Look at the warnings from your compiler. (If your compiler doesn't show a warning for this code, look up how to configure it to show useful warnings.)
a.c:5:5: warning: incompatible pointer to integer conversion assigning to 'int'
from 'int (const char *, ...)' [-Wint-conversion]
x = printf;
^ ~~~~~~
1 warning generated.
printf is a function. Every function can be used as a pointer to that function. A pointer to a function is a way to refer to the function that can be placed into a variable. Typically, it's the address of the code of the function in memory.
It's possible to assign a pointer to an integer. The resulting value depends on your system. The integer is typically the address of the code of the function in memory.
There's nothing useful you can do with this value except in some very particular circumstances (such as crafting binary exploits, or managing dynamic code loading). Anything you can do with the value would be very specific to a particular hardware and software environment.

What does "char *p, *getenv();" do? Why a function with no args in a variable declaration line?

I'm reading a bit of code in C, and in the variable declaration line, there's "char *p, *getenv();"
I understand "char *p" of course. What does "char *getenv()" do? Later on in the code, the function getenv() is called with a variable passed to it. But what's the point of "char *getenv();" without any arguments?
Sorry if this is basic. I'm just starting to learn C.
It is "valid C" (I would almost say "unfortunately") - but it is not particularly useful. It is a "declaration without declaration" - "I will be using a function getenv() but I'm not going to tell you what the arguments will be". It does have the advantage of preventing a compiler warning / error - something that would normally be prevented with a "real" function prototype, for example by including the appropriate .h file (in this case, stdlib.h).
To clarify: the following code
#include <stdio.h>
int main(void) {
char *p;
p = getenv("PATH");
printf("the path is %s\n", p);
return 0;
}
will throw a compiler warning (and you should never ignore compiler warnings):
nonsense.c: In function ‘main’:
nonsense.c:5: warning: implicit declaration of function ‘getenv’
nonsense.c:5: warning: assignment makes pointer from integer without a cast
Either adding #include <stdlib.h> or the line you had above, will make the warning go away (even with -Wall -pedantic compiler flags). The compiler will know what to do with the return value - and it figures out the type of the arguments on the fly because it knows the type when it sees it.
And that is the key point: until you tell the compiler the type of the return value of the function it does not know what to do (it will assume int, and make appropriate conversions for the variable you are assigning to - this can be inappropriate. For example, a pointer is often bigger than an int, so information will be lost in the conversion.)
It's a declaration (an old-style one without a prototype, since the argument list is missing) for the function getenv. Aside from being arguably bad style to hide a function declaration alongside the declaration of an object like this, it's bad to omit the prototype and bad not to be using the standard headers (stdlib.h in this case) to get the declarations of standard functions.

How to pass an array of gmp_z to a function without a warning?

Background
I'm using the C interface to the GMP library and I have a need to manipulate arrays of integers. Main type for integers in the GMP library is mpz_t, and GMP is using a trick to allow the users to use gmp_z without explicit allocation, while being able to pass them around as pointers. Namely the gmp_z type is defined as follows.
typedef struct
{
int _mp_alloc;
int _mp_size;
mp_limb_t *_mp_d;
} __mpz_struct;
typedef __mpz_struct mpz_t[1];
This is neat, but I am having trouble passing arrays of mpz_t to functions that operate on const arrays.
Example
To exemplify consider this simple non-GMP program.
#include <stdio.h>
typedef struct {
int x;
} x_struct;
typedef x_struct x_t[1];
void init_x(x_t x) {
x->x = 23;
}
void print_x(const x_t x) {
printf("x = %d\n", x->x);
}
// I'm just printing so taking a const array
void print_x_array(const x_t* x_array, size_t n) {
size_t i;
for (i = 0; i < n; ++ i) {
printf("x[%zu] = %d\n", i, x_array[i]->x);
}
}
int main() {
x_t x; // I can declare x and it's allocated on the stack
init_x(x);
print_x(x); // Since x is an array, pointer is passed
x_t x_array[3];
init_x(x_array[0]);
init_x(x_array[1]);
init_x(x_array[2]);
print_x_array(x_array, 3); // Compile warning
}
The program uses the GMP trick, just showing off the usage. Compiling this program gives an annoying warning
gcc test.c -o test
test.c: In function ‘main’:
test.c:33:3: warning: passing argument 1 of ‘print_x_array’ from incompatible pointer type [enabled by default]
test.c:17:6: note: expected ‘const struct x_struct (*)[1]’ but argument is of type ‘struct x_struct (*)[1]’
Question
Since I'm not a C expert, can someone please shed more light on why this warning is happening at all. More importantly, is there a way to get around this warning while still using mpz_t (or x_t in the example)?
Just cast it to const:
print_x_array((const x_t *)x_array, 3); // Should be ok
First, let's note that the compiler warning you are getting has absolutely nothing to do with GMP, their strategy of typedefing a mpz_t type as an array of size one so that it facilitates some function calls within the library (but only facilitates scalar argument passing), nor to the passing of arrays to functions, and nor its a real problem in itself actually.
The problem all relies on the const declaration of function parameter input, and that is not a true issue. Its good to have that definition, so compiler will balk if function writer attempts to modify the object being passed to the function. But burden cannot be put on function callers!
In my setting (OpenSUSE, x86_64, gcc version 9.2.1) your code does not gives a warning and works perfectly fine if I don't use the -pedantic compiler option. This is because, as Michael Pankov stated, the (old) C standard is pretty tight and sometimes cumbersome, while compilers today are very smart. The compiler does now what you want, and will provide you correct code, be assured of that. Also, in your environment it seems there will be many more people calling the function than changing it, so it can be quite assured the input will not be unduely modified, and you can ignore the warning altogether.
For ignoring this specific warning check here for GCC, other compilers also provide this options.
About the const on function parameter input check here, I particularly like this answer: "If your code has many people working on it and your functions are non-trivial then you should mark const any and everything that you can. When writing industrial-strength code, you should always assume that your coworkers are psychopaths trying to get you any way they can (especially since it's often yourself in the future).".

error: conflicting types for ‘six’ with gcc

Receiving error: conflicting types for ‘six’ when attempting to compile.
void main(){
const int k = 4;
six(&k);
}
float * six(const int *x)
{
float *p = malloc(sizeof(float));
*p = (float)*x;
return p;
}
Here is what is going on.
When the compiler does not encounter a prototype for a function before a call to it, it deduces the prototype from the call itself, and assumes the return type to be int. This is what it does in your example.
Later it finds the definition of the function, and it finds that the return type is actually float, which does not match with the prototype it has deduced earlier. Hence the error of conflicting types (instead of, say, missing prototype).
The solution is to, of course, provide a prototype for the function before a call to it is made.
You didn't declare six to the compiler before you called it, so the compiler was forced to guess what the signature of six is (typically, this is something like int func()). When it saw the actual declaration, it threw an error because the actual function declaration didn't match its implicit declaration.
You need to declare functions before they are used; place a declaration like
float *six(const int *x);
before main.
Solution to your problem
Just add the following declaration before main():
float *six(const int *x);
Or put your float *six(const int *x) definition before the main() function.
Why the compiler complain conflicting types
Since there is no declaration of your six() function before the compiler compile the main function, it will deduce the prototype from the function callsite, and will assume the return type to be int. And when it compiles your six() function, the compiler will find two function with the same name but different return type, so it complain the conflicting types error.
Thanks to Ziffusion's comment.
why to adjust your code in the above way
You should declare/define each of your element before use in C.
For your currently code, you need to declare your function type before the main function, so that the compiler knows what six() is when compile the main function.
Why there should be a declaration before use in C
For variables and other data types, since C is strong typed. When the variable is used, it need to be declared first, so that the compiler knows what type the variable is, and could do data type check.
For functions, since the C compiler compiles the code function by function, and will generate a function call statement in the assembly, so the compiler need to know the function parameter and return value data type, so that it could generated correct instructions to do parameter passing, and return value restoring. Normally, the compiler will compile the function in a source code file one by one from the start of the file to the end of the file, so you need to declare the function type before use it.

How do I quiet the C compiler about a function pointer takes any number of arguments?

I have a function pointer inside a struct that gets dynamically set at runtime to the address of another function in various places in my code. It is defined in my header file like this:
void *(*run)();
During compile time, I get the following warning about this:
warning: function declaration isn't a prototype
This warning is benign, because the pointer is used in many places in my code to call the function it points to, and everything works just fine. However, I would really like to silence the warning.
If I change it to this:
void *(*run)(void);
I get compile errors whever I use it, because the various functions that make use of the pointer have different numbers of arguments, and saying void inside the parenthesies tells the compiler it accepts no arguments.
I can't use a va_list or anything fancy like that, as this is simply a pointer to another function, and I use a single pointer for them all because it keeps the code clean and simple.
I can silence the warning with adding this to my compiler flags:
-Wno-strict-prototypes
But I'd rather not have to disable compiler warnings with flags if I can avoid it.
So my question is: How do I notate this function pointer in the code in such a way that the compiler is satisfied with the fact that it accepts any number of any kind of arguments?
The code works perfectly. I just want the warning to go away.
Store the pointer as a void * and cast to the appropriate function pointer type when necessary? Keep in mind that it isn't necessarily safe to call one type of function pointer as if it were another type, so the warning you're starting out with isn't entirely invalid.
You can cast a function pointer like so:
void *genericPointer = ...;
void (*fp)(int, int) = genericPointer;
fp(123, 456);
Note that:
There's no explicit casting necessary here, as void * can always be cast to any pointer type.
The initial "void" before (*fp) is the return type of the function pointer.
You are trying to do things clean - i.e. involve the compiler in checks, but the design you invented simply cannot be clean by its principle. You cannot involve compiler in prototype checks this way, because you always must know, which parameters to pass at this particular case in runtime. Compiler cannot check this and if you make a mistake, segmentation fault is on the way.
But if I remember well, something like this was maybe used also in linux kernel (?). The solution is to have a general pointer (like the one you have) and each time you call a particular function you just typecast it to the pointer to function with the particular arguments. You may need to typecast it to void * first to silence the compiler again :-)
In C, when you call a function without a prototype visible, default argument promotions are applied to all of the arguments that you pass to the function. This means that the types that you actually pass do not necessarily match the types received by the function.
E.g.
void (*g)();
void f()
{
float x = 0.5;
g(x); // double passed
}
This means that you need to know that the function that you are actually calling has a compatible signature to that implied by the arguments that you are passing after promotion.
Given that you need to know this in any case you must know the function signature of the actual function being called at the call site which is using the function pointer. With this knowledge it is usually simpler and cleaner to use a function pointer with the correct prototype and you can avoid default argument promotion entirely.
Note that as you are defining your functions with prototypes, when you assigned a pointer to your function to a function pointer without a prototype you effective converted, say, a void(*)(int, int) to a void(*)() so it is completely correct and desirable to perform the reverse conversion before calling the function. gcc allows both these conversions without emitting any warnings.
E.g.
void PerformCall( void(*p)() )
{
if (some_condition)
{
// due to extra knowledge I now know p takes two int arguments
// so use a function pointer with the correct prototype.
void(*prototyped_p)(int, int) = p;
prototyped_p( 3, 4 );
}
}
Try typedefing the function pointer declaration and then have the caller explicityly cast it:
typedef void *(*run)();
//when calling...
void my_foo() {}
run r = (run)my_foo;
If the different function signatures are known, use a union. Otherwise, use a pointer of type void (*)(void) (actually, any function pointer type would do) to hold the generic pointer and convert to the proper type when setting the value and calling the code.
Example using a union:
union run_fn
{
void *(*as_unary)(int);
void *(*as_binary)(int, int);
};
struct foo
{
union run_fn run;
};
void *bar(int, int);
struct foo foo;
foo.run.as_binary = bar;
void *baz = foo.run.as_binary(42, -1);
Example using explicit casts:
struct foo
{
void (*run)(void);
};
void *bar(int, int);
struct foo foo;
foo.run = (void *(*)(int, int))bar;
void *baz = ((void *(*)(int, int))foo.run)(42, -1);
Don't use a void * to hold function pointers - such a conversion is unspecified by the ISO C standard and may be unavailable on certain architectures.
Ignoring the warning and using your code as-is is actually also a possibility, but keep in mind that any function argument will be subject to the default argument promotions and it's your responsibility that the promoted arguments properly match the declared parameters.

Resources