passing a two-dimmensional array to function - c

I am trying to compile the following simple code in Workbench:
1. typedef float matrixType[3][3]
2.
3. void my_func(matrixType matrix)
4. {
5. printf("matrix[0][0] = %g\n",matrix[0][0]);
6. }
7.
8. void main()
9. {
10. matrixType my_matrix = {{0,1,2},{3,4,5},{6,7,8}};
11. matrixType* ptr_matrix = &my_matrix;
12.
13. my_func(*ptr_matrix);
14. }
I receive the following warning:
test.c:13: warning: passing arg 1 of `my_func' from incompatible pointer type
I can't understand, what am I doing wrong. The compilation of the same code in Visual Studio works without any warnings, but in Workbench something is going wrong.
Thanks.

With gcc (GCC) 4.5.3 with all warnings turned on it also compiles fine after making the following changes:
Add a semicolon after the first line.
Add #include <stdio.h> at top.
Change the return type of main to int.
Add return 0; as the last line.
The void main() is not correct C even though it appears in various books, manuals, and web tutorials. On some architectures it will cause strange problems, usually as the program terminates.
Taking the address of an array type is challenging the workbench type checker. I'm not going to drag out the C standard to figure out if the workbench warning is correct. It's probably a bug.
But I'm pretty sure that if you recode this way you will see no errors with any compiler:
#include <stdio.h>
typedef float rowType[3];
typedef rowType matrixType[3];
void my_func(matrixType matrix)
{
printf("matrix[0][0] = %g\n",matrix[0][0]);
}
int main()
{
matrixType my_matrix = {{0,1,2},{3,4,5},{6,7,8}};
rowType* ptr_matrix = my_matrix;
my_func(ptr_matrix);
return 0;
}
The reason is that my_matrix is automatically converted to a pointer to it's first element in the assignment
rowType* ptr_matrix = my_matrix;
This is just as in
char s[] = "hello world!";
char *p = s;
the array name s is converted to a pointer to its first element.
The parameter in void my_func(matrixType matrix) has a type identical to rowType* because all arrays are also passed as pointers to first elements. So all the types in this code must match in a way that's very clearly defined in the C standard. &my_matrix may not be incorrect, but it's an "edge case" more likely to expose type checking bugs.

You are missing a semicolon at the end of line 1.

Related

Pointers in C and casting

I've started learning pointers this time. Im trying to read bytes from this array. Task is almost done but CLang keep warns me with warning I don't understand. Here's my code.
Warning says : " Function call argument is an uninitialized value"
int main(void)
{
int tab[] = {67305985,134678021,202050057};
int *pp=0;
pp=tab;
char *wsk=(char*)pp;
for (int i = 0; i < 12; i++)
{
if((wsk+i)!=(void*)NULL)
printf("%d ",*(wsk+i)); // warning on this line
else
return 0;
}
}
These warnings are from Clang Static Analyzer (or whatever they call it these days).
It looks like a false positive to me, if we assume that int is at least 4 bytes and the real code has #include <stdio.h> and no other changes.
If you're using the latest version of the analyzer, you could file a clang bug report. Well -- you could if they allowed people who don't already have accounts to file bug reports. Maybe someone else reading this thread can do it.
Note: it would help the question to post exactly which version of the analyzer you are running (this may be different to the compiler you're using to build -- some IDEs use different compilers for building than for these inline messages).
This if statement
if((wsk+i)!=(void*)NULL)
does not make sense. The macro NULL is already a null pointer constant. So there is no sense to cast it to void *.
And the pointer wsk+i can not be equal to NULL in this loop because initially it points to an object.
Just remove the if statement and output each character in the loop.
And it is a bad idea to use magic numbers like 12 used in the loop.
You could write for example
const size_t N = sizeof( tab ) / sizeof( *tab );
and then in the loop
for ( size_t i = 0; i < N * sizeof( int ); i++ )
//...
As for the warning then it is irrelative to the presented code provided that you included the header <stdio.h>.
wsk will never be null, since you've set it to be the same as tab (arrays, in C/C++ are just pointers to a block of data. The warning is telling you that no matter how much you add to wsk it will always be non-null. What you need to do is limit your iterations in the loop to the number of valid items in the array, since C/C++ arrays have no terminators of any kind.
The printf might just be confusing CLang. Try printf("%d ", wsk[i]);

Why function call only pass the first argument

I'm trying to call a function (on line 15) just via a cast but only the first argument is getting passed, how could I fix it?
I tried to change the float value "2" to 2.0f to declare it's a float and not an int but it's still not working.
!Note that the code is horrible because it's a code golf, the line 15 has to be in a dll form later, this code here is just a test program to avoid launching the target process multiples times. Here's my actual code with a score of 58 chars
DllMain(a,b,c){((int(*)(int,float))927309216)(‭7903472‬,2);}
#include <Windows.h>
#include <stdio.h>
char * sSkelModelStencil = "SkelModelStencil"; //here I reproduce the char like it is in the memory
void SetConsoleFloat(const char *sKey, float fVal) //this is the reproduction of SetConsoleFloat in CShell.dll
{
printf("arg1: %s arg2: %f\n", sKey, fVal); //printing the arguments getting passed into the function
return;
}
int main()
{
while (1) {
SetConsoleFloat("SkelModelStencil", 2); //calling the reproduction function
((int(*)())SetConsoleFloat)(sSkelModelStencil,2); //calling the reproduction function via a cast & using SetConsoleFloat addr
system("PAUSE");
}
}
In some architectures, the way arguments are passed depends on the way they're declared. For instance, special registers may be used for float parameters. It's the declaration of the function type that matters, not the declaration of the argument expression.
The parameter signature () is different from (const char *sKey, float fVal), and as a result the fVal argument is being passed differently from the way the function expects to receive it.
First of all - this is atrocious code, don't do that.
Secondly - compile your code with compiler warnings on, so the compiler can tell you where you might be going wrong. Of course, you need a proper C compiler (which MSVC is not, in case you were using that). gcc will tell you:
a.c:15:10: warning: function called through a non-compatible type
But, to answer your question: You're casting into the wrong type of function: You're using the function type void (); but you need void (const char*, float). So, try:
((void(*)(const char*, float))SetConsoleFloat)(sSkelModelStencil,2);
instead of your existing line 15. It's also a good idea to separate casts from type definitions of functions - for clarity - so you would have:
typedef void (*scf_function_t)(const char*, float);
earlier, and then:
((scf_function_t) SetConsoleFloat)(sSkelModelStencil,2);
but again - there's really no good reason to do any of this in the first place.

Function pointer returning a pointer of some type in C

I am having trouble solving this below piece of code.
When i compile the entire file with this below piece of code included, i see a warning ( shown below), which i don't see if excluded from the entire *.c file.
CODE:
int * ( * get_ptr1)(int) = (int* )0x234456;
printf("The address of the func_ptr is %x\n", get_ptr1);
Warning message:
Initialization from incompatible pointer type
Could anyone please explain me why i am seeing this warning and what need to be corrected in the above code. I am using a C99 standard compiler.
Please bear with me if my title is not very specific to what i have asked.
int * and int *(*)(int) are different types. You could write:
int *(*get_ptr1)(int) = (int *(*)(int))0x234456;
There is no format specifier for function pointers with printf. Your use of %x causes undefined behaviour. See this thread for some ideas.

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).".

Why this code below fails

#include <stdio.h>
int *top;
int a=1;
top=&a;
void main()
{
printf("%d\n",*top);
}
error C2440: 'initializing' : cannot convert from 'int *' to 'int'
UPDATE
I know how to make it work,but I'm asking why it DOESN'T work.
You're actually tripping over the compiler's support for ancient C syntax. The original C compiler allowed declarations without a type, defaulting it to int. So outside of any function,
foo;
would declare a global int variable called foo. So when you say
top = &a;
it declares a global int variable called top and tries to initialize it with the address of a. This gives you the two errors you see -- two conflicting declarations for top and an inability to convert an int * to an int. Of course those same ancient C compilers would not give you the second error, happily converting the address to an int without complaint.
This also tells you why int i; i = 100; works --- its two declarations for i as a global int variable (which is ok, as they're the same type), and the second initializes it to 100 (which is ok as only one declaration has an initializer)
There's lots of fascinating stuff in Dennis Ritchie's The Development of the C Language
I'm a bit surprised at the exact error message you got about it, but the problem (or at least one of the obvious problems) is that outside of a function, you're allowed to define and initialize variables, but you're not allowed to do a normal assignment -- that has to be done as part of executing a function. As such, your top=&a; isn't allowed.
Another problem is that you have main returning void, where it should return an int (though most compilers will accept that without even a warning, not to mention an error message).
Actually, from your original code:
int *top;
int a=1;
top=&a;
As others have mentioned - in global space you can declare, or declare and initialize. You can not do assignment.
What is actually happening in the line top = &a; is that you are actually re-declaring a variable called top, and it defaults to the int type. The compiler should actually warn about creating a new variable named top that has the same name as a previously declared variable, as well as generate an additional warning that you are creating a variable of default type int.
In C, variables that are declared without a type default to int, and that would generate the error you see.
error C2440: 'initializing' : cannot convert from 'int *' to 'int'
What this is really complaining about is that top = &a; as in your code actually looks like int top = &a; to the compiler, so you are trying to bind an int* to int.
This works:
#include <stdio.h>
int *top;
int a=1;
int main()
{
top=&a;
printf("%d\n",*top);
}
You need to be sure not do global assignment like that. You can only do initialization, nothing else for global variables.
You also have not mentioned the other errors, please mention all errors, sometimes one error is based of another and when one is fixed the others get fixed. In this case it was:
Conflicting types for 'top'.
Another option:
#include <stdio.h>
int a=1;
int *top=&a;
void main()
{
printf("%d\n",*top);
}
I honestly have no idea why that fails, but this works:
#include <stdio.h>
int a = 1;
int* top = &a;
void main()
{
printf("%d\n", *top);
}
And remember: ALWAYS INITIALIZE YOUR POINTERS!!
If you're not going to assign them immediately, at least do something like this:
int* top = 0;

Resources