As a beginner in C, I learned a fancy way to allocate the memory with struct{} to replace something like ch1Buffer = calloc(u32Size, sizeof *ch1Buffer);and put them outside of the int main{} to boost up the calculation speed.
However, I got an error on my variable x saying: This declaration has no storage class or type specifier, you can see the annotation on the side of the code. Should I declared the variable x or?
Here is my example code:
#include <stdio.h>
// New way for memory allocation
struct {
float ch1Buffer;
double ch2Buffer;
double ch2newBuffer;
} *x;
x = calloc(10, sizeof * x); // The error happened on the left side "x": This declaration has no storage class or type specifier
int main()
{
int i,n;
const int u32Size = 10;
float* ch1Buffer = NULL;
double* ch2Buffer = NULL;
double* ch2newBuffer=NULL;
int pBuffer[] = { 10,2,10,2,10,5,10,5,10,2 };
int* pi16Buffer = pBuffer;
// Old way for memory allocation
//ch1Buffer = (float*)calloc(u32Size, sizeof* ch1Buffer);
//ch2Buffer = (double*)calloc(u32Size, sizeof* ch2Buffer);
//ch2newBuffer = (double*)calloc(u32Size, sizeof * ch2Buffer);
// De-interveal the data to ch1Buffer and ch2Buffer
for (i = 0; i < u32Size/2; i++)
{
ch1Buffer[i] += pi16Buffer[i * 2];
ch2Buffer[i] += pi16Buffer[i * 2 + 1];
}
// Use memcpy to pick out the data we are interested
memcpy(ch2newBuffer, &ch2Buffer[2], 2 * sizeof(ch2Buffer[0]));
for (i = 0; i < 2; i++)
{
printf("a[%d] = %f\n", i, *ch2newBuffer);
ch2newBuffer++;
}
free(ch1Buffer);
free(ch2Buffer);
return 0;
}
You can't do a malloc or calloc outside main or any other function. You can declare it at the beginning of your code if you need it as a global variable but you'll need to allocate the memory inside the main for example.
typedef struct mystruct {
float ch1Buffer;
double ch2Buffer;
double ch2newBuffer;
}mystruct;
mystruct* x;
int main (void) {
x = calloc(10, sizeof(mystruct)); // array of your structs
if (!x) { // always check calloc return value
perror("calloc");
exit(EXIT_FAILURE);
}
/* do stuff */
return 0;
}
Also I would suggest giving self-explanatory names to your structs for a better understanding of what it represents.
This gives you a example to use components of each members. Similar to the above anwers, the pointer is defined as a global, and allocated in main(). This Not a good pratice, just for demo.
#include <stdio.h>
#include <stdlib.h>
#define SIZE 10
struct xxx {
float f1;
double d2;
double d3;
};
typedef struct xxx mytype;
mytype *x;
void print_mytype()
{
int i;
for (i=0; i<SIZE; i++) printf("x[%d] = %f, %lf, %lf\n", i, x[i].f1, x[i].d2, x[i].d3);
return;
}
void setdata()
{
int i;
for (i=0; i<SIZE; i++)
{
x[i].f1 = rand()/(float)RAND_MAX;
x[i].d2 = rand()/(double)RAND_MAX;
x[i].d3 = rand()/(double)RAND_MAX;
}
}
int main()
{
x = calloc(SIZE, sizeof(mytype));
setdata();
print_mytype();
free(x);
return 0;
}
the posted code does not compile!
Here is what the compiler says about the code:
gcc -ggdb3 -Wall -Wextra -Wconversion -pedantic -std=gnu11 -c "untitled1.c" -o "untitled1.o"
untitled1.c:9:1: warning: data definition has no type or storage class
9 | x = calloc(10, sizeof * x); // The error happened on the left side "x": This declaration has no storage class or type specifier
| ^
untitled1.c:9:1: warning: type defaults to ‘int’ in declaration of ‘x’ [-Wimplicit-int]
untitled1.c:9:1: error: conflicting types for ‘x’
untitled1.c:8:4: note: previous declaration of ‘x’ was here
8 | } *x;
| ^
untitled1.c:9:5: warning: implicit declaration of function ‘calloc’ [-Wimplicit-function-declaration]
9 | x = calloc(10, sizeof * x); // The error happened on the left side "x": This declaration has no storage class or type specifier
| ^~~~~~
untitled1.c:9:5: warning: incompatible implicit declaration of built-in function ‘calloc’
untitled1.c:2:1: note: include ‘<stdlib.h>’ or provide a declaration of ‘calloc’
1 | #include <stdio.h>
+++ |+#include <stdlib.h>
2 |
untitled1.c:9:23: error: invalid type argument of unary ‘*’ (have ‘int’)
9 | x = calloc(10, sizeof * x); // The error happened on the left side "x": This declaration has no storage class or type specifier
| ^~~
untitled1.c: In function ‘main’:
untitled1.c:33:22: warning: conversion from ‘int’ to ‘float’ may change value [-Wconversion]
33 | ch1Buffer[i] += pi16Buffer[i * 2];
| ^~
untitled1.c:38:5: warning: implicit declaration of function ‘memcpy’ [-Wimplicit-function-declaration]
38 | memcpy(ch2newBuffer, &ch2Buffer[2], 2 * sizeof(ch2Buffer[0]));
| ^~~~~~
untitled1.c:38:5: warning: incompatible implicit declaration of built-in function ‘memcpy’
untitled1.c:2:1: note: include ‘<string.h>’ or provide a declaration of ‘memcpy’
1 | #include <stdio.h>
+++ |+#include <string.h>
2 |
untitled1.c:47:5: warning: implicit declaration of function ‘free’ [-Wimplicit-function-declaration]
47 | free(ch1Buffer);
| ^~~~
untitled1.c:47:5: warning: incompatible implicit declaration of built-in function ‘free’
untitled1.c:47:5: note: include ‘<stdlib.h>’ or provide a declaration of ‘free’
untitled1.c:13:11: warning: unused variable ‘n’ [-Wunused-variable]
13 | int i,n;
| ^
Compilation failed.
Suggest you fix those problems in the code, that you can, before asking us about any problems that you cannot fix.
As the error messages say:
add the statement:
#include <stdlib.h>
add the statement:
#include <string.h>
We are unlikely to help you when the code you post clearly indicates that you have not put any effort into solving the problem(s) your self.
Related
Zero errors and warnings, if I add printf() inside the push() function, it prints 5 and 7 as I want it to, but when I use it in main() I get 0 and 0.
typedef struct Point {
double x, y;
} Point;
typedef struct Stack {
int size;
Point p[];
} Stack;
void push(Stack* stack, double value1, double value2)
{
stack->size = stack->size++;
stack->p[stack->size].x = value1;
stack->p[stack->size].y = value2;
}
int main(void)
{
Stack stack;
Point p;
stack.size = 0;
stack.p[stack.size].x = 0;
stack.p[stack.size].y = 0;
push(&stack, 5, 7);
printf("%f, %f", &stack.p[stack.size].x, &stack.p[stack.size].y);
}
Zero errors and warnings
Use a better compiler, or learn how to use yours (unfortunately many compilers run in low-warning mode by default).
$ gcc -O -Wall -Wextra -Werror a.c
a.c: In function ‘push’:
a.c:12:17: error: operation on ‘stack->size’ may be undefined [-Werror=sequence-point]
12 | stack->size = stack->size++;
| ~~~~~~~~~~~~^~~~~~~~~~~~~~~
a.c: In function ‘main’:
a.c:25:5: error: implicit declaration of function ‘printf’ [-Werror=implicit-function-declaration]
25 | printf("%f, %f", &stack.p[stack.size].x, &stack.p[stack.size].y);
| ^~~~~~
a.c:25:5: error: incompatible implicit declaration of built-in function ‘printf’ [-Werror]
a.c:1:1: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
+++ |+#include <stdio.h>
1 | typedef struct Point {
a.c:25:14: error: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘double *’ [-Werror=format=]
25 | printf("%f, %f", &stack.p[stack.size].x, &stack.p[stack.size].y);
| ~^ ~~~~~~~~~~~~~~~~~~~~~~
| | |
| double double *
a.c:25:18: error: format ‘%f’ expects argument of type ‘double’, but argument 3 has type ‘double *’ [-Werror=format=]
25 | printf("%f, %f", &stack.p[stack.size].x, &stack.p[stack.size].y);
| ~^ ~~~~~~~~~~~~~~~~~~~~~~
| | |
| double double *
a.c:20:11: error: unused variable ‘p’ [-Werror=unused-variable]
20 | Point p;
| ^
cc1: all warnings being treated as errors
Let's see what the errors mean.
a.c:12:17: error: operation on ‘stack->size’ may be undefined [-Werror=sequence-point]
12 | stack->size = stack->size++;
stack->size++ means add one to stack->size, but if the value of this expression is used, it's the old value of stack->size. You use this expressions in an instruction that also assigns to stack->size. Generally speaking, when there are two assignments to the same variable or memory location (e.g. a structure field or an array element) in the same instruction, the behavior is undefined. “Undefined behavior” means that anything can happen. Some plausible behaviors include:
This doesn't modify stack->size at all, because the compiler generated code for: 1. read old value; 2. store the result of ++; 3. assign with =.
This adds 1 to stack->size, because the compiler generated code for: 1. read old value; 2. assign with =; 3. store the result of ++.
This adds 2 to stack->size, because the compiler generated code for: 1. read old value for ++; 2. store the result of ++; 3. read old value for =; 4. store the result of =.
But other weirder behaviors are possible, including:
Using different values for stack->size below, because the compiler has inconsistent knowledge about what the value of stack->size is after this instruction.
The compiler deciding not to generate any code for the push function because since it's attempting to do something that's forbidden, the function must be called only in some particular case that can't happen with these particular build options.
Demons come out of your nose (if you have an adequate peripheral on your computer).
You obviously meant to add 1 to stack->size. So write either
++stack->size;
or
stack->size++;
or
stack->size += 1;
But only one of these. Don't mix them.
a.c:25:5: error: implicit declaration of function ‘printf’ [-Werror=implicit-function-declaration]
25 | printf("%f, %f", &stack.p[stack.size].x, &stack.p[stack.size].y);
| ^~~~~~
a.c:25:5: error: incompatible implicit declaration of built-in function ‘printf’ [-Werror]
a.c:1:1: note: include ‘<stdio.h>’ or provide a declaration of ‘printf’
+++ |+#include <stdio.h>
That one's easy: the compiler gives you the answer. Include stdio.h. The bit about “incompatible implicit declaration” is because since the declaration of printf was missing, the compiler guessed one, but it guessed wrong. The guessing rules date back from half a century ago and are not particularly useful, never rely on them.
a.c:25:14: error: format ‘%f’ expects argument of type ‘double’, but argument 2 has type ‘double *’ [-Werror=format=]
25 | printf("%f, %f", &stack.p[stack.size].x, &stack.p[stack.size].y);
| ~^ ~~~~~~~~~~~~~~~~~~~~~~
| | |
| double double *
Here the compiler tells you what's wrong, and it should be easy to figure out what to do. To print a floating-point number, pass a floating-point value, not a pointer to one. So:
printf("%f, %f", stack.p[stack.size].x, stack.p[stack.size].y);
a.c:20:11: error: unused variable ‘p’ [-Werror=unused-variable]
That one means what it says. You declared a variable p but never use it. Just remove its declaration.
With the corrections above, your program might work, although there's one more problem that the compiler can't detect.
typedef struct Stack {
int size;
Point p[];
} Stack;
…
Stack stack;
This reserves zero entries in memory for Stack.p. It might work for you if your compiler decided to place the variable Point p immediately after Stack stack in memory, but that's heavily dependent on the compiler, on the presence of other variables, on the variable names, etc. You can't use a flexible array member like Point p[] in a local variable, only in memory allocated with malloc (in most cases). To keep things simple, start with a statically allocated size for the stack.
#define MAXIMUM_STACK_SIZE 42
typedef struct Stack {
int size;
Point p[MAXIMUM_STACK_SIZE];
} Stack;
Then your stack can grow up to that many elements.
Do you really need a flexible array member?
If not, then you could declare your Point array struct data member as a pointer, and after taking care of incrementing size of stack and printing without references as I saw in my other answer, then use malloc() to dynamically allocate memory for your array (in this example I only allocate for 1 Point, but you can easily generalize it), like this:
#include <stdio.h>
#include <stdlib.h>
typedef struct Point {
double x, y;
} Point;
typedef struct Stack {
int size;
Point* p;
} Stack;
void push(Stack* stack, double value1, double value2)
{
stack->size++;
stack->p[stack->size].x = value1;
stack->p[stack->size].y = value2;
}
int main(void)
{
Stack stack;
// 1 for 1 Point
stack.p = malloc(1 * sizeof(Point));
stack.size = 0;
stack.p[stack.size].x = 0;
stack.p[stack.size].y = 0;
push(&stack, 5, 7);
printf("%f, %f", stack.p[stack.size].x, stack.p[stack.size].y);
free(stack.p);
return 0;
}
Output:
5.000000, 7.000000
You do not initialize the flexible array member of your stack.
Change:
stack->size = stack->size++;
which invokes Undefined Behavior, to:
stack->size++;
Moreover, you need to remove the &s from printf("%f, %f", &stack.p[stack.size].x, &stack.p[stack.size].y);.
Putting everything together, we get:
#include <stdio.h>
#include <stdlib.h>
typedef struct Point {
double x, y;
} Point;
typedef struct Stack {
int size;
Point p[];
} Stack;
void push(Stack* stack, double value1, double value2)
{
stack->size++;
stack->p[stack->size].x = value1;
stack->p[stack->size].y = value2;
}
int main(void)
{
// 1 for 1 Point
Stack *stack = malloc(sizeof(Stack) + sizeof(Point) * 1);
stack->size = 0;
stack->p[stack->size].x = 0;
stack->p[stack->size].y = 0;
push(stack, 5, 7);
printf("%f, %f", stack->p[stack->size].x, stack->p[stack->size].y);
free(stack);
return 0;
}
Output:
5.000000, 7.000000
Read more in https://wiki.sei.cmu.edu/confluence/display/c/DCL38-C.+Use+the+correct+syntax+when+declaring+a+flexible+array+member
I am currently compiling this on Ubuntu and when i compile this program
#include <stdio.h>
struct vector { float x,y,z; };
struct vector V_new2(x,y,z){
struct vector thenew;
thenew.x = x;
thenew.y = y;
thenew.z = z;
return thenew;
}
float* V_new1(x,y,z){
float thenew[3];
thenew[0] = x;
thenew[1] = y;
thenew[2] = z;
return thenew;
}
int main()
{
float *v1 = V_new1(5,6,7);
struct vector v2 = V_new2(1,2,3);
printf("v1 : (%f,%f,%f)\n",v1[0],v1[1],v1[2]);
printf("v2 : (%f,%f,%f)\n",v2.x, v2.y, v2.z);
return 0;
}
I get these messages in the terminal and in another compiler i simply got Segmentation fault after adding the codes inside the main function.
w.c: In function ‘V_new2’:
w.c:5:15: warning: type of ‘x’ defaults to ‘int’ [-Wimplicit-int]
struct vector V_new2(x,y,z){
^~~~~~
w.c:5:15: warning: type of ‘y’ defaults to ‘int’ [-Wimplicit-int]
w.c:5:15: warning: type of ‘z’ defaults to ‘int’ [-Wimplicit-int]
w.c: In function ‘V_new1’:
w.c:13:8: warning: type of ‘x’ defaults to ‘int’ [-Wimplicit-int]
float* V_new1(x,y,z){
^~~~~~
w.c:13:8: warning: type of ‘y’ defaults to ‘int’ [-Wimplicit-int]
w.c:13:8: warning: type of ‘z’ defaults to ‘int’ [-Wimplicit-int]
w.c:18:12: warning: function returns address of local variable [-Wreturn-local-addr]
return thenew;
How do i fix this?
float thenew[3]; is local to function as warning explains. You need to allocate memory for it on the heap (float *thenew = malloc(sizeof(float) * 3);, you'll also need #include <stdlib.h>) or use global variable (not recommended).
I am trying to code a basic zero threshold function. such that if the value of the array element is greater than zero must remain same else it must be zero. But my problem is with passing the array values from main to the function using pointers. Here's the snippet. im is the input array and im2 is the array to store result. t is the threshold which is 0 and m is the order. On passing the input array from main to thresh function. I just checked the values of im in thresh function but all were showing 0, as commented in code below, instead of original values. where am i going wrong??
int thresh(double *im[], double *im2[], int t, int m)
{
int i, j;
printf("im:%f", im[0]); //here i am getting output as zero instead of 1
for (i = 0; i < m; i++)
{
if (im[i] > t)
im2[i] = im[i];
else
im2[i] = 0;
}
return 0;
}
int main()
{
float im[4] = { 1,-2,3,-4 };
float im2[4];
int th = 0;
thresh((float*)im, (float*)im2, th, 2);
getch();
return 0;
}
Turn on compiler warnings and read them. They are there to help. This is what I got on compilation:
$ gcc main.c
main.c: In function ‘thresh’:
main.c:10:23: warning: comparison between pointer and integer
if (im[i] > t)
^
main.c: In function ‘main’:
main.c:24:12: warning: passing argument 1 of ‘thresh’ from incompatible pointer type [-Wincompatible-pointer-types]
thresh((float*)im, (float*)im2, th, 2);
^
main.c:4:5: note: expected ‘double **’ but argument is of type ‘float *’
int thresh(double *im[], double *im2[], int t, int m)
^~~~~~
main.c:24:24: warning: passing argument 2 of ‘thresh’ from incompatible pointer type [-Wincompatible-pointer-types]
thresh((float*)im, (float*)im2, th, 2);
^
main.c:4:5: note: expected ‘double **’ but argument is of type ‘float *’
int thresh(double *im[], double *im2[], int t, int m)
^~~~~~
So there is some stuff to fix.
First of, the prototype for thresh should be int thresh(double *im, double *im2, int t, int m) or even better int thresh(const double *im, double *im2, int t, int m)
Second, why are you mixing float and double? Stick to one, and stick to double unless you have a really good reason.
I have found an example of multi thread programming which help to determine the prime numbers for a given integar n.it will also take number of thread as a input from the user.But the problem is when i try to execute it give me some errors which very hard to solve.Can anyone help?I am newbies at coding so any type of help and advice will be greatly appreciated.
#include <stdio.h>
#include <math.h>
#include <pthread.h> // required for threads usage
#define MAX_N 100000000
#define MAX_THREADS 25
int nthreads, n, prime[MAX_N+1], nextbase; // next sieve multiplier to be used
// lock for the shared variable nextbase
pthread_mutex_t nextbaselock = PTHREAD_MUTEX_INITIALIZER;
// ID structs for the threads
pthread_t id[MAX_THREADS];
// "crosses out" all odd multiples of k
void crossout(int k)
{ int i;
for (i = 3; i*k <= n; i += 2) {
prime[i*k] = 0;
}
}
// each thread runs this routine
void *worker(int tn) // tn is the thread number (0,1,...)
{ int lim,base,
work = 0; // amount of work done by this thread
// no need to check multipliers bigger than sqrt(n)
lim = sqrt(n);
do {
pthread_mutex_lock(&nextbaselock);
base = nextbase;
nextbase += 2;
// unlock the lock
pthread_mutex_unlock(&nextbaselock);
if (base <= lim) {
// don't bother crossing out if base known composite
if (prime[base]) {
crossout(base);
work++; // log work done by this thread
}
}
else return work;
} while (1);
}
main(int argc, char **argv)
{ int nprimes, // number of primes found
i,work;
n = atoi(argv[1]);
nthreads = atoi(argv[2]);
for (i = 3; i <= n; i++) {
if (i%2 == 0) prime[i] = 0;
else prime[i] = 1;
}
nextbase = 3;
// get threads started
for (i = 0; i < nthreads; i++) {
pthread_create(&id[i],NULL,worker,i);
}
for (i = 0; i < nthreads; i++) {
pthread_join(id[i],&work);
printf("%d values of base done\n",work);
}
nprimes = 1;
for (i = 3; i <= n; i++)
if (prime[i]) {
nprimes++;
}
printf("the number of primes found was %d\n",nprimes);
}
I have the following error while compiling:
In function ‘worker’:
Primes.c:67:12: warning: return makes pointer from integer without a cast [enabled by default]
else return work;
^
Primes.c: In function ‘main’:
Primes.c:88:7: warning: passing argument 3 of ‘pthread_create’ from incompatible pointer type [enabled by default]
pthread_create(&id[i],NULL,worker,i);
^
In file included from Primes.c:15:0:
/usr/include/pthread.h:244:12: note: expected ‘void * (*)(void *)’ but argument is of type ‘void * (*)(int)’
extern int pthread_create (pthread_t *__restrict __newthread,
^
Primes.c:88:7: warning: passing argument 4 of ‘pthread_create’ makes pointer from integer without a cast [enabled by default]
pthread_create(&id[i],NULL,worker,i);
^
In file included from Primes.c:15:0:
/usr/include/pthread.h:244:12: note: expected ‘void * __restrict__’ but argument is of type ‘int’
using: gcc -c -Wall -Wextra -Wconversion -std=gnu99 %f
where %f is the name of the file being compiled
The compiler output the following messages.
I added some commentary for each message that should point you to how to fix the problem.
compiler warning message:
:28:14: warning: conversion to 'int' from 'double' may alter its' value [-Wconversion]
lim = sqrt(n);
The function: sqrt() returns a 'double' but 'lim' is declared a 'int'
Suggest: cast the returned value to 'int'
lim = (int)sqrt(n);
compiler warning message:
:43:12: warning: return makes pointer from integer without a cast [enbled by default]
else return work;
the return type from the worker() function is void*
always exit the worker() function by:
pthread_exit( &work );
compiler warning message:
:24:18: warning: unused parameter 'tn' [-Wunused-parameter]
means the parameter 'tn' is not used. fix this by inserting in that function the line:
(void)tn;
compiler warning message:
47:1: warning: return type defaults to 'int' [enabled by default]
The signature of the main() function is not correct. without using the environment parameter, (almost never used), there are only 2 valid main() signatures and one optional signature.
use the correct signature for what your program needs.
int main( void )
int main( int argc, char *argv[] )
int main() // optional signature
compiler warning message:
50:4: warning: implicit declaration of function 'atoi' [-Wimplicit-function-declaration]
means the header file: stdlib.h has not been #include'd suggest inserting at top of file:
#include <stdlib.h>
compiler warning message:
61:7: warning: passing argument 3 of 'pthread_create' from incompatible pointer type [enabled by default]
means the third parameter to the function: pthread_create() was not a void pointer. suggest:
pthread_create(&id[i],NULL,worker,(void*)&i);
compiler warning message:
67:7: warning: passing argument 2 of 'pthread_join' from incompatible pointer type [enabled by default]
means the variable 'work' should be declared, in file global space, not in the thread function, as:
void * work;
there are other compiler warning messages output, but the above will eliminate them.
I.E. always start with the first compiler message, fix that, then re-compile. then fix the new first message.
Most of the problems with the syntax of the code could have been avoided by paying attention to the man pages for the system functions that were called in the posted code.
Note: the crossout() functions' logic is not correct. the code needs to start at k+k, continue until k<=n and step by k+=k I.E.
for( int k=i+i; k<(n+1); k+=k )
the code seems to be trying to implement a eratosthenes sieve for prime numbers google for the details.
unless your required to use threads, don't, they will just slow things down due to all the context swapping, etc.
this code logic:
for (i = 3; i <= n; i++)
{
if (i%2 == 0) prime[i] = 0;
else prime[i] = 1;
}
seems to be wrong, for one thing, the array prime[] will be initially all 0 because it is in the file global space. As far as I can tell, that code block is not needed at all.
because the work variable will be in the file global space, suggest an array of
void* work[ nthreads ];
then have the thread function: worker() actually use the passed parameter to select which of the entries in the array to be updating.
I have the following versions of passing 2D array as pointer.
Version 1
#include <stdio.h>
void disp(int a[][5])
{
printf("a[0][3] = %d\n", a[0][3]); /* a[0][3] = 4 */
}
int main ()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
disp(a);
return 0;
}
Version 2
#include <stdio.h>
typedef void(*callDisplay)(int*);
void disp(int a[][5])
{
printf("a[0][3] = %d\n", a[0][3]); /* a[0][3] = 4 */
}
int main ()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
callDisplay fn = (callDisplay) &disp;
fn(a);
return 0;
}
Version 1 rises warning incompatible pointer type. expected int (*)[5] but argument is of type int * as expected. However, (Version 2) calling the same function with pointer is compiling without any such warnings.
gcc options: gcc -O0 -g3 -Wall -c -fmessage-length=0
Could somebody pass light on this?
If you remove the cast when assigning the function pointer you get:
tmp.c: In function ‘main’:
tmp.c:13:22: warning: initialization from incompatible pointer type [enabled by default]
callDisplay fn = &disp;
The cast is suppressing this warning even though by casting to a function pointer of a different type you have invoked undefined behavior when you call the function pointer. Basically, you should never need to cast a function pointer as it will hide any warnings like this.
If you fix the function pointer you get the following code:
typedef void(*callDisplay)(int[][5]);
void disp(int a[][5])
{
printf("a[0][3] = %d\n", a[0][3]); /* a[0][3] = 4 */
}
int main ()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
callDisplay fn = &disp;
fn(a);
return 0;
}
Which when you compile you get the same warning as your first example:
tmp.c: In function ‘main’:
tmp.c:14:5: warning: passing argument 1 of ‘fn’ from incompatible pointer type [enabled by default]
fn(a);
^
tmp.c:14:5: note: expected ‘int (*)[5]’ but argument is of type ‘int *’
This function declaration
typedef void(*callDisplay)(int*);
has compatible argument when is called like
fn(a);
The problem is related to this casting
callDisplay fn = (callDisplay) &disp;
it is wrong.
That is the program has undefined behaviour.
According to the C Standard (6.3.2.3 Pointers)
8 A pointer to a function of one type may be converted to a pointer to
a function of another type and back again; the result shall compare
equal to the original pointer. If a converted pointer is used to
call a function whose type is not compatible with the referenced type,
the behavior is undefined.