error: field has incomplete type

jamie

I am attempting to port a library to Mac OS X. The compiler is reporting an incomplete type error. Specifically: field has incomplete type 'header_t []. However, when I look at the source code, header_t is defined just before packet_state_t, where packet_state_t references header_t. Thus, there shouldn't be any forward reference error, since header_t is clearly defined at the point at which it is referenced inside packet_state_t. The line in which the error occurs is marked with ERROR below. How to resolve?

 typedef struct header_t {
    uint8_t  hdr_id;         // header ID

    uint8_t  hdr_prefix;     // length of the prefix (preamble) before the header
    uint8_t  hdr_gap;        // length of the gap between header and payload
    uint16_t  hdr_flags;      // flags for this header
    uint16_t hdr_postfix;    // length of the postfix (trailer) after the payload
    uint32_t hdr_offset;     // offset into the packet_t->data buffer
    uint32_t hdr_length;     // length of the header in packet_t->data buffer
    uint32_t hdr_payload;    // length of the payload

    uint8_t   hdr_subcount;  // number of sub-headers
    header_t  *hdr_subheader;   // Index of the first subheader in packet_t

    jobject  hdr_analysis;   // Java JAnalysis based object if not null
} header_t;

typedef struct packet_state_t {
    flow_key_t pkt_flow_key; // Flow key calculated for this packet, must be first
    uint8_t pkt_flags;       // flags for this packet
    jobject pkt_analysis;    // Java JAnalysis based object if not null
    uint64_t pkt_frame_num;  // Packet's frame number assigned by scanner
    uint64_t pkt_header_map; // bit map of presence of headers

    uint32_t pkt_wirelen;    // Original packet size
    uint32_t pkt_buflen;     // Captured length

    int8_t pkt_header_count; // total number of main headers found
    header_t pkt_headers[];  // One per header + 1 more for payload ERROR HERE!!!

    int8_t pkt_subheader_count;  // total number of sub headers found
    header_t pkt_subheaders[];  // One per header + 1 more for payload
} packet_state_t;
Adam Rosenfield

The type header_t is just fine, but the compiler is actually complaining about the type header_t[], i.e. "array of indeterminate length of header_t", which has an incomplete type because the compiler doesn't know how big it is (it couldn't possibly).

C99 (but not C89) supports what's called a flexible array member in structures, which is exactly this, but only at the end of a structure:

struct X {
  // any member declarations
  ...
  AnyType lastMemberArray[];  // This must be the LAST member
};

This is allowed, but it makes the structure you declared also an incomplete type because again, the compiler doesn't know how big it is. The only way to use it is to dynamically allocate memory of the required size or to cast an already allocated block of memory. For example:

// Allocate an X instance with space for 3 members in lastMemberArray:
X *x = malloc(sizeof(X) + 3 * sizeof(AnyType));
// Can now use x->lastMemberArray[0] through x->lastMemberArray[2]
...

// Alternatively:
char buffer[sizeof(X) + 3 * sizeof(AnyType)];
X *x = (X *)buffer;
// Same as above

Why does the flexible array member have to come last in the struct? Imagine if other members came after it. How could the compiler generate code to access those members?

// If this were allowed:
struct X {
  AnyType flexibleArray[];
  int memberAfter;
};

void doSomething(X *x) {
  // How does the compiler generate code for this?  It doesn't know what offset
  // memberAfter is from the start of the object, because the array doesn't
  // have a known size
  printf("memberAfter = %d\n", x->memberAfter);
}

Hence, you can't have a structure with more than one flexible array member, because then clearly one of them wouldn't be the last structure member, so your definition is not allowed.

Whatever library code you're writing, it couldn't have used two flexible array members to begin with, or it wouldn't have compiled on any platform. I suggest you investigate the original code to find out what it did; if it's using standard ISO C features without relying on any platform-specific or implementation-specific behavior or extensions, you should have no trouble porting it.

Without being able to see the original code, I'd recommend you switch from using an inline flexible array member to a dynamically allocated array with a pointer, at least for the first array (and probably also the second for consistency):

typedef struct packet_state_t {
    flow_key_t pkt_flow_key; // Flow key calculated for this packet, must be first
    uint8_t pkt_flags;       // flags for this packet
    jobject pkt_analysis;    // Java JAnalysis based object if not null
    uint64_t pkt_frame_num;  // Packet's frame number assigned by scanner
    uint64_t pkt_header_map; // bit map of presence of headers

    uint32_t pkt_wirelen;    // Original packet size
    uint32_t pkt_buflen;     // Captured length

    int8_t pkt_header_count; // total number of main headers found
    header_t *pkt_headers;   // POINTER here, not an array

    int8_t pkt_subheader_count;  // total number of sub headers found
    header_t *pkt_subheaders;    // POINTER here, not an array
} packet_state_t;

EDIT

I downloaded the jnetpcap code and compiled it on Linux to see what happened. To my surprise, it compiled. The compiler command invoked was:

gcc -c -fPIC -DLIBPCAP_VERSION=0x1532 -I/tmp/jnetpcap/build/include -I/tmp/jnetpcap/src/c -I/usr/lib/jvm/default-java/include -I/usr/lib/jvm/default-java/include/linux /tmp/jnetpcap/src/c/jnetpcap.cpp /tmp/jnetpcap/src/c/packet_flow.cpp /tmp/jnetpcap/src/c/packet_jheader.cpp /tmp/jnetpcap/src/c/jnetpcap_pcap_header.cpp /tmp/jnetpcap/src/c/nio_jbuffer.cpp /tmp/jnetpcap/src/c/winpcap_stat_ex.cpp /tmp/jnetpcap/src/c/winpcap_send_queue.cpp /tmp/jnetpcap/src/c/winpcap_ext.cpp /tmp/jnetpcap/src/c/util_debug.cpp /tmp/jnetpcap/src/c/util_crc16.c /tmp/jnetpcap/src/c/jnetpcap_ids.cpp /tmp/jnetpcap/src/c/jnetpcap_dumper.cpp /tmp/jnetpcap/src/c/jnetpcap_utils.cpp /tmp/jnetpcap/src/c/util_in_cksum.cpp /tmp/jnetpcap/src/c/jnetpcap_beta.cpp /tmp/jnetpcap/src/c/nio_jmemory.cpp /tmp/jnetpcap/src/c/util_crc32.c /tmp/jnetpcap/src/c/packet_jsmall_scanner.cpp /tmp/jnetpcap/src/c/mac_addr_sys.c /tmp/jnetpcap/src/c/packet_protocol.cpp /tmp/jnetpcap/src/c/nio_jnumber.cpp /tmp/jnetpcap/src/c/packet_jheader_scanner.cpp /tmp/jnetpcap/src/c/library.cpp /tmp/jnetpcap/src/c/packet_jscan.cpp /tmp/jnetpcap/src/c/jnetpcap_pcap100.cpp /tmp/jnetpcap/src/c/mac_addr_dlpi.c /tmp/jnetpcap/src/c/util_checksum.cpp /tmp/jnetpcap/src/c/packet_jpacket.cpp /tmp/jnetpcap/src/c/winpcap_ids.cpp /tmp/jnetpcap/src/c/jnetpcap_bpf.cpp

So the first thing that's going on here is that this is C++, not C. C++ does not support flexible array members at all, although some compilers support them as extensions. C++03 §9.2/8 says:

[...] When an array is used as the type of a nonstatic member all dimensions shall be specified.

And C++11 §9.2/9 says:

9 Non-static (9.4) data members shall not have incomplete types. [...]

When I compile this code in g++ 4.8.2 with a higher warning level (-Wall -Wextra pedantic), it warns as follows:

In file included from /tmp/jnetpcap/src/c/packet_jscan.cpp:28:0:
/tmp/jnetpcap/src/c/packet_jscanner.h:287:23: warning: ISO C++ forbids zero-size array ‘pkt_headers’ [-Wpedantic]
  header_t pkt_headers[];  // One per header + 1 more for payload
                       ^
/tmp/jnetpcap/src/c/packet_jscanner.h:290:26: warning: ISO C++ forbids zero-size array ‘pkt_subheaders’ [-Wpedantic]
  header_t pkt_subheaders[];  // One per header + 1 more for payload

So what g++ is doing (contrary to the C++ standard) is converting the arrays of unspecified size to arrays of size 0. The first one (pkt_headers) works exactly like the flexible array member in C99, in that if you've allocated the proper amount of memory, you can access the array members of that normally up to the maximum size. But if you ever access any members after that (particularly pkt_subheader_count and pkt_subheaders), the compiler generates code as if pkt_headers had size 0, i.e. if the struct were equivalent to this:

typedef struct packet_state_t {
    flow_key_t pkt_flow_key; // Flow key calculated for this packet, must be first
    uint8_t pkt_flags;       // flags for this packet
    jobject pkt_analysis;    // Java JAnalysis based object if not null
    uint64_t pkt_frame_num;  // Packet's frame number assigned by scanner
    uint64_t pkt_header_map; // bit map of presence of headers

    uint32_t pkt_wirelen;    // Original packet size
    uint32_t pkt_buflen;     // Captured length

    int8_t pkt_header_count; // total number of main headers found
    // NOTHING HERE (array of size 0)

    int8_t pkt_subheader_count;  // total number of sub headers found
    header_t pkt_subheaders[];  // One per header + 1 more for payload
} packet_state_t;

Which would cause accesses to pkt_subheader_count (and probably also access to pkt_subheaders) to access the exact same memory as as pkt_headers[0].

Why does the happen to work out ok? Because the code in this project never accesses pkt_subheader_count or pkt_subheaders anywhere. If it did, the code wouldn't work for the reasons described above unless it got extraordinarily lucky. And it's not valid C++, it just happens to be accepted by the compiler.

Solution? Just remove pkt_subheader_count and pkt_subheaders from the structure declaration. They're not used anywhere in code, and removing them allows pkt_headers[] to be the last member of the structure, so it's a valid flexible array member, which is valid C99 or a non-standard compiler extension in C++.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related

From Dev

error: field has incomplete type

From Dev

field has incomplete type error - forward declaration

From Dev

g++ error: field has incomplete type

From Dev

Error: field has incomplete type in C

From Dev

Field has incomplete type?

From Dev

Field has incomplete type?

From Dev

Field has an incomplete type: int*[]

From Dev

error: field ‘m_ssmmap’ has incomplete type C++

From Dev

Getting “field has incomplete type” and "conflicting types"

From Dev

C++: Field has incomplete type

From Dev

C++: Field has incomplete type

From Dev

How to fix an "field has incomplete type" error when using a forward declaration

From Dev

How to resolve "parameter has incomplete type" error?

From Dev

Getting "field has incomplete type" even after adding forward reference

From Dev

Error with struct option: array type has incomplete element type

From Dev

error: aggregate ‘food_type a’ has incomplete type and cannot be defined

From Dev

QFile has incomplete type

From Dev

Error : aggregate 'first one' has incomplete type and cannot be defined

From Dev

Variable has incomplete type 'struct my_error_mgr'

From Dev

SQLite Incomplete Type Error

From Dev

Error: incomplete type is not allowed

From Dev

Error: incomplete type is not allowed

From Dev

Incomplete type is not allowed error

From Dev

Error: Output field 'XXXX' is incomplete

From Dev

"error array type has incomplete element type" for a Two-dimensional array

From Dev

"error array type has incomplete element type" for a Two-dimensional array

From Dev

Array type has incomplete element type?

From Dev

Incomplete type is not allowed error and a tuple

From Dev

Error: deferencing pointer to incomplete type

Related Related

HotTag

Archive