1

I'm trying to pass a struct by reference but no matter what I do I'm running into errors. I think I have the prototyping and declaration and the pointers all screwed up.

This is for an Arduino project of mine. The code works fine on the Arduino compiler but doesn't compile on Pelles C compiler.

#include <stdio.h>
#include <string.h>
#include <stdint.h>

void Fault_Bits_To_Flags(uint8_t Master_Fault_Byte, struct Fault_Flag_Struct *Fault_Flag);

struct Fault_Flag_Struct {
    char Fault_Name[30];
    uint8_t Fault_State;
};
struct Fault_Flag_Struct Fault_Flag [7];

int main(void) {
    uint8_t Master_Fault_Byte = 181;

    strcpy(Fault_Flag[0].Fault_Name, "fault 0");
    Fault_Flag[0].Fault_State = 1;

    strcpy(Fault_Flag[1]....
    strcpy(Fault_Flag[2]....
    strcpy(Fault_Flag[3]....
    strcpy(Fault_Flag[4]....

    Fault_Bits_To_Flags( Master_Fault_Byte, *Fault_Flag);
    return 0;
}

//Puts 8 bits from single byte into 8 separate bytes (flags)//
void Fault_Bits_To_Flags(uint8_t Master_Fault_Byte, struct Fault_Flag_Struct *Fault_Flag) {
    for ( int i = 0; i < 8; i++ )
        {
            Fault_Flag[i].Fault_State = (Master_Fault_Byte >> i) & 1;
    }
}

error #2140: Type error in argument 2 to 'Fault_Bits_To_Flags';
expected '(incomplete) struct Fault_Flag_Struct *' but found 'struct
Fault_Flag_Struct'.

error #2120: Redeclaration of 'Fault_Bits_To_Flags', previously declared at Reference.c(4); expected 'void function(unsigned char, (incomplete) struct Fault_Flag_Struct *)' but found 'void function(unsigned char, struct Fault_Flag_Struct )'. Error code: 1 *

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
  • 1
    You have to put `void Fault_Bits_To_Flags(uint8_t Master_Fault_Byte, struct Fault_Flag_Struct *Fault_Flag);` after the definition of the `struct`. – mch Aug 29 '19 at 08:34
  • Please indent your code properly – klutt Aug 29 '19 at 08:54
  • The code posted does not match the errors posted. The two second error message indicates that the routine was first declared with a pointer for the second parameter but was subsequently defined with a structure parameter. But the code posted shows a pointer in the definition. – Eric Postpischil Aug 29 '19 at 11:20
  • Please always take care to show exact error messages and to indicate where in your code the message was shown. – Gerhardh Aug 29 '19 at 11:36
  • BTW you also have a buffer overflow. The array `Fault_Flag`is 7 elements long and you travel 8 element in function `Fault_Bits_To_Flags – Guillaume Petitjean Aug 29 '19 at 13:40

2 Answers2

2

The scope of a parameter declaration in the list of parameters of a function prototype terminates at the end of the function declarator. Opposite to C++ there is no such a notion as the elaborated type specifier in C.

From the C Standard (6.2.1 Scopes of identifiers)

  1. ... If the declarator or type specifier that declares the identifier appears within the list of parameter declarations in a function prototype (not part of a function definition), the identifier has function prototype scope, which terminates at the end of the function declarator

So the type specifier struct Fault_Flag_Struct used in the function prototype

void Fault_Bits_To_Flags(uint8_t Master_Fault_Byte, struct 
Fault_Flag_Struct *Fault_Flag);

denotes a different entity compared with the declaration that follows the function prototype

struct Fault_Flag_Struct {
char Fault_Name[30];
uint8_t Fault_State;
};

So you have to exchange the placements of the declarations.

Also this call

Fault_Bits_To_Flags( Master_Fault_Byte, *Fault_Flag);

is invalid because the type of the expression *Fault_Flag is struct Fault_Flag_Struct while the function expects the type struct Fault_Flag_Struct *. That is instead of a pointer to an object of the type struct Fault_Flag_Struct you are passing the object itself.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
1

Scope and Structure Types

There are two problems in the code shown.

The first is because C has some odd rules about structure definitions. One rule, in C 2018 6.7.2.3 4, is that structure declarations with the same tag (the name after struct) declare the same type (a structure type with that name) only if they have the same scope:

All declarations of structure, union, or enumerated types that have the same scope and use the same tag declare the same type.…

When you declare a structure inside a function declaration, like this:

void foo(struct X *p);

Then the scope of X is function prototype scope. Per 6.2.1 4, this scope ends at the end of the function declaration. Then, when you later define the structure, as with:

struct X { int q; }

it is in a different scope, and, per the rule above, the struct X in the function declaration is not the same type as the struct X in the later definition. One way to fix this is to move the structure definition prior to the function declaration. It also suffices merely to declare the structure tag prior to the function declaration, as with:

struct X;
void foo(struct X *p);

To fully understand what is happening here, we should consider two other issues. One issue is that we could have struct X in two different translation units (different source files compiled separately), and calling a function defined with a struct X * parameter in one unit from another unit that defines struct X is allowed. This is because that, although the two struct X types in the two translations units are different, they are compatible. 6.2.7 1 says:

… Moreover, two structure, union, or enumerated types declared in separate translation units are compatible if…

Oddly, this rule only applies to structures declared in separate translation units. If we defined void foo(struct X *p { … } prior to defining struct X in one translation unit, they are different and incompatible types, but, if we define them in separate units, they are compatible types!

The second issue is how can this code work when the structure declarations have separate scopes:

struct X;
void foo(struct X *p);

The first struct X has file scope (per 6.2.1 4), and the second struct X has function prototype scope. The rule in 6.7.2.3 4 only applies if the declarations have the same scope, so it does not say these declare the same struct X. Instead, there is another rule, in 6.7.2.3 9:

If a type specifier of the form struct-or-union identifier or enum identifier occurs other than as part of one of the above forms, and a declaration of the identifier as a tag is visible, then it specifies the same type as that other declaration, and does not redeclare the tag.

(The “above forms” are definitions or stand-alone declarations.) This causes the struct X in the function declaration after a prior file-scope struct X to specify the same type.

Error in Argument

The second error is in the second argument passed to the function in this statement:

Fault_Bits_To_Flags( Master_Fault_Byte, *Fault_Flag);

Fault_Flag is an array, so *Fault_Flag is the first element of the array. This is a structure, not a pointer. To pass a pointer to the first element of the array, use:

Fault_Bits_To_Flags( Master_Fault_Byte, Fault_Flag);
Community
  • 1
  • 1
Eric Postpischil
  • 195,579
  • 13
  • 168
  • 312