3

I get the following error with gcc when I declare a struct netif * from a function scope (where the compile doesn't complain) to global scope:

src/main.c:114:3: warning: passing argument 1 of 'low_level_init' from incompatible pointer type [enabled by default]
src/main.c:62:13: note: expected 'struct netif *' but argument is of type 'struct netif *'

Why is does compiler give the following "non-sensical" complaint?

expected 'stuct netif *' but argument is of type 'struct netif *'

Randomblue
  • 112,777
  • 145
  • 353
  • 547
  • 6
    Please post the code for a minimal repro of this compile error – Steve Townsend May 01 '12 at 13:55
  • In addition to a minimal, complete example that reproduces the error it might be helpful to know which version of GCC this is. Is it a snapshot/pre-release included with some distribution? The warning style looks fairly recent. – Flexo May 01 '12 at 13:57
  • 4
    Maybe the definition for `struct netif` in scope at both places is for a different one? – pmg May 01 '12 at 13:57
  • @pmg - I thought gcc had a different warning for that. (I don't think I can even think of a way to make it not an error) – Flexo May 01 '12 at 14:00

4 Answers4

4

This "full program"

void foonetif(struct netif *dst) {
  if (dst) return;
  return;
}

struct netif {
  double bar;
};

int main(void) {
  struct netif *netif = 0; /* NULL */
  foonetif(netif);
  return 0;
}

generates this output from gcc 10398683.c (gcc version 4.6.3), so with all default options

10398683.c:1:22: warning: ‘struct netif’ declared inside parameter list [enabled by default]
10398683.c:1:22: warning: its scope is only this definition or declaration, which is probably not what you want [enabled by default]
10398683.c: In function ‘main’:
10398683.c:12:3: warning: passing argument 1 of ‘newnetif’ from incompatible pointer type [enabled by default]
10398683.c:1:6: note: expected ‘struct netif *’ but argument is of type ‘struct netif *’

Note the last warning (really a note) :)

pmg
  • 106,608
  • 13
  • 126
  • 198
2

The problem is scope. The first struct netif is in the scope of the function's argument list, and goes out of scope after that function ends. The second struct netif is defined in a new scope. These are thereby different structure types with different tags which happen to have the same name. Just like int i; and int i; in two different functions are different variables that happen to have the same name.

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
1

An interesting question; have fallen foul of this myself; mostly due to horrid hacks involving dubious type casts on innocent memory-blocks.


This answer is really just a corollary to R's answer, which pretty much nails the issue (though i'm not quite sure about the and goes out of scope after that function ends.. bit)

For me, the key to this is perusal of:
(1) ISO C99 6.7.2:

Two types have compatible type if their types are the same. Additional rules for determining whether two types are compatible are described in 6.7.2 for type specifiers, in 6.7.3 for type qualifiers, and in 6.7.5 for declarators.46) Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if their tags and members satisfy the following requirements: If one is declared with a tag, the other shall be declared with the same tag. ...


(2) C namespaces


Anyway, here's some code (~a couple of translation units) that hopefully demonstrates some possibly surprising behaviour for those that haven't yet hit this issue before:

blah.c:

#include <stdio.h>

struct bar  {int a; int b;} stbar; 
struct bar_ {int a; int d;} stbar_; 

void foo(struct bar* pst);
void foo_(struct bar st);


void callfoo() 
{ 
    /*no warnings; possibly surprising results ! */
    stbar.a=313;
    stbar.b=31313;
    foo(&stbar);
    printf("called foo() with stbar:  %d, %d\n", stbar.a, stbar.b);

    /*generates incompatible types warnings:
    blah.c:23:5: warning: passing argument 1 of ‘foo’ from incompatible pointer type [enabled by default]
    blah.c:6:6: note: expected ‘struct bar *’ but argument is of type ‘struct bar_ *’    */
    stbar_.a=313;
    stbar_.d=31313;
    foo(&stbar_);
    printf("called foo() with stbar_: %d, %d\n", stbar_.a, stbar_.d);


    /*generates incompatible types warnings:
    blah.c:31:5: warning: passing argument 1 of ‘foo’ from incompatible pointer type [enabled by default]
    blah.c:6:6: note: expected ‘struct bar *’ but argument is of type ‘struct bar *’      */
    struct bar  {float s; float t;} stbar; 
    foo(&stbar);
    printf("called foo() with locally defined stbar:  %f, %f\n", stbar.s, stbar.t);    
}


void callfoo_()
{
    stbar.a=313;
    stbar.b=31313;

    //passing in incompatible type by value ~ no warnings; possibly surprising results ! 
    foo_(stbar); 

    /*uncomenting next line generates compiler error: 
    blah.c:47:5: error: incompatible type for argument 1 of ‘foo_’
    blah.c:7:6: note: expected ‘struct bar’ but argument is of type ‘struct bar_’     */
    //foo_(stbar_); 
}


void main() 
{
    callfoo();
    callfoo_();
}

blah_.c:

#include <stdio.h>

struct bar {int x; float z;} stbar; 

void foo(struct bar* pst)
{
    printf("foo : %d, %f\n", pst->x, pst->z);
    pst->x=13;
    pst->z=13.13;
}

void foo_(struct bar st)
{
    printf("foo_ : %d, %f\n", st.x, st.z);
    st.x=13;
    st.z=13.13;
}

output:

$ gcc  blah.c blah_.c
blah.c: In function ‘callfoo’:
blah.c:23:5: warning: passing argument 1 of ‘foo’ from incompatible pointer type [enabled by default]
blah.c:6:6: note: expected ‘struct bar *’ but argument is of type ‘struct bar_ *’
blah.c:31:5: warning: passing argument 1 of ‘foo’ from incompatible pointer type [enabled by default]
blah.c:6:6: note: expected ‘struct bar *’ but argument is of type ‘struct bar *’

$ ./a.out
foo : 313, 0.000000
called foo() with stbar:  13, 1095898235
foo : 313, 0.000000
called foo() with stbar_: 13, 1095898235
foo : 13274075, 0.000000
called foo() with locally defined stbar:  0.000000, 13.130000
foo_ : 313, 0.000000

$ gcc --version
gcc (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1 ...


Corollary of corollary: praise the gods for C++ namespaces.

Community
  • 1
  • 1
violet313
  • 1,912
  • 1
  • 15
  • 19
0

Your "full program" wont compile.

struct netif is not declared before foonetif which uses it. Try moving the struct definition before its first use.

Neil
  • 11,059
  • 3
  • 31
  • 56
  • The "full program" compiles just fine (albeit with warnings). Notice that what is used in `foonetif` is a pointer, not an object of type `struct netif`. – pmg May 01 '12 at 15:09
  • The compiler will create an 'empty' `struct netif` for itself when it first comes across one if there hasn't been one defined yet. When it comes across a real definition, they don't match. Therefore you get the warning. I suspect this wouldn't work if you compiled it as C++ rather than C. – Neil May 02 '12 at 11:20