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;
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++.
In definition of struct header_t
Change
header_t *hdr_subheader; // Index of the first subheader in packet_t
to
struct header_t *hdr_subheader; // Index of the first subheader in packet_t
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 months ago.
Improve this question
Please give me the answer. Thanks
struct ZMessage {
uint8_t id[sizeof(struct ZID)];
struct ZBlock block[1]; //what different 'ZBlock block'
};
C and C++ are different languages.
struct ZBlock block[1]; is a C syntax.
In classic C a name of struct is ... not a type. It's a name of block (of variables). C got concept of anonymous struct. Anonymous structs allowed to create separate block of variables or fields with proper alignment, i.e following Test would have field b started from a new word, i.e. size of block will be 4 if size of short is 2.
// this is correct ONLY in C
int main(void)
{
struct Test {
short a : 5;
struct {
short b : 5;
short c : 6;
};
};
// you can have a name of variable matching a name of block.
// regardless of name, declaration without struct is forbidden
struct Test Test;
Test.b = 3;
printf("Test.b equals to %d, size of test %d", Test.b, sizeof(Test));
// Output: Test.b equals to 3, size of test 4
return EXIT_SUCCESS;
}
Therefore in any context where you declare a variable or function parameter you have to precede struct-id by keyword struct to create a type-id.
In C++ struct is a class-type. It's name can be used as type-id, so you don't need a keyword struct. C++ doesn't allow anonymous structs but allows anonymous unions and anonymous namespace.
In fact that you declare ZMessage without a typedef suggest that it is C++ context or a recent C version. C syntax is supported for backward compatibility of header files.
About array of size 1. In that case expression consisting out of name block is a pointer to array of ZBlock. Using size 1 to declare a flexible array according to C standard is no longer correct.
C had a special rule that you can use pointer arithmetics (and operator[] as extent of that) to access implicitly allocated memory after this struct, if array is the last member of struct and got incomplete type.
In most situations, the flexible array member is ignored. In
particular, the size of the structure is as if the flexible array
member were omitted except that it may have more trailing padding than
the omission would imply
Creation of such might look like this:
// might have size 4 or size 8 - greater than sizeof(short)
struct Test {
short size;
short data[]; // Incomplete array type - C11.
// `short data[1]; is NO longer a flexible array.
};
int count = 10;
// note: C doesn't support Test::data construct
// C++ would require a type cast (Test*)
struct Test* pack = malloc(sizeof(struct Test) + count*sizeof(short));
pack->size = count;
pack->data[0] = 4;
pack->data[1] = 8;
...
Here is a problem with padding. We most likely allocate more memory than we need. correct way is to determine offset of address beyond last element of data[]. In C, while sizeof(Test) can be, e.g. 8, offset of data[0] can be still 2.
// such usage of offsetof is undefined in C++
struct Test* pack = malloc(offsetof(struct Test, data[count]));
C++ explicitly doesn't allow to go beyond boundary of object, i.e. beyond boundary of struct. But some compilers support it as extension, usually with no array size declared in that case or with size 1 in case of some compilers. Caveat with those is that it's not consistent if compiler assumes struct to include first member of single array or array can have a zero length.
I was writing a code the other day,to do some vector math. That used dynamically allocated structure members. The code that initialized instances of of such structures had to somehow know whether or not the instances was already initialized or not.
I used the following method...
The file vector.h includes among other things...
File: "vector.h"
#include<stdint.h>
#include"complex.h" // struct cplx defined here
#define SET 0x00
#define UNSET 0x01
struct vector {
struct cplx *res; // for resolution vectors
uint8_t status;
uint8_t dim; // dimension of vector
};
typedef struct vector Vector;
void setvector(Vector *vec,int _dim,...);
//ellipsis contains pairs of double values representing the complex magnitude of each resolution vector in order.
And file "setvector.c" ...
#include<stdarg.h>
#include"vector.h"
#include<limits.h>
#include<stdlib.h>
void setvector (Vector *vec,int _dim,...)
{
if(vec->status != SET){
vec->res = calloc(vec->dim = (uint8_t)_dim, sizeof(*vec->res));
vec->status = SET;
}
va_list dptr;
va_start (dptr, _dim);
/*blah..blah..blah........
.....some code......*/
//To modify already set vectors
vec->res = realloc(vec->res,(vec->dim = (uint8_t)_dim) * sizeof(*vec->res));
/*..blah...*/
va_end(dptr);
}
Suppose a instance of a vector object is initialized locally (run-time) in some function (e.g main), then their is a small chance that the structure member status which is supposed to contain "garbage value" on initialization, has the same value as the macro SET. To be presize, for type uint8_t assuming all values have equal probability, the chance of this "garbage value" to be equal to SET is exactly one in 256 i.e 1/256. This would mean that the routine setvector would fail - by calling realloc without calling calloc - at least once every 256 calls to it. (This would lead to a program that failed randomly with segmentation fault error, for no apparent reason). This chance can be reduced by setting status to 4 byte int to once every 2^32 calls, But that will be just evading the problem, not solving it.
Is there any way to create routines in C that will initialize a structure instance without this problem.
for example, by setting default values to structure members ?
Thx in advance :-).
I know this issue can be resolved by resorting to C++ structures, and their constructors functions, .(I think c++ structures support default values, but I'm not sure).
But I'm trying to do it in C.
Is there any way to create routines in C that will initialize a
structure instance without this problem. for example, by setting
default values to structure members ?
Yes, you can use designated initializers on most modern (C99+) compilers.
Hence, from within a function, you could do this:
Vector v = {.status = UNSET};
setvector(&v, n);
More info on designated initializers here
I was looking to make a struct which was an arbitrary size, known at compile time. (for use in a macro).
eg:
/* assume sizeof(SomeStruct) could be an odd number,
* if it is using GCC's 'packed' attribute for eg */
struct {
unsigned char data[sizeof(SomeStruct)];
} a, *tmp;
tmp = (void *)some_data
a = *tmp;
However I was concerned that struct padding may increase the size of the struct so it is larger than the member, I was assured that the size of a single member struct will always be the size of its member.
So my question is:
Can I rely on single member structs always being the same size as their member? Is this apart of the C spec? or is it just how most compilers behave?
C11 6.7.2.1 paragraph 17:
There may be unnamed padding at the end of a structure or union.
No special case is listed for structs with only one member. This is implementation-defined.
It's not obvious why a compiler would put padding there though, since the size of the member should already be as padded as is necessary for all purposes, as it has a complete type of its own.
For your usage though, you don't need to rely on the compiler's behaviour - you can enforce it yourself by adding a static assertion to your macro that sizeof *tmp == sizeof (SomeStruct). If you have an up-to-date compiler and your macro allows for declaration statements, just use _Static_assert; there are also several C99-compatible hacks you can use, such as:
#define STATIC_EXPR_ASSERT(COND) (sizeof (char[(COND) ? 1 : -1]))
... which you can use as the lhs of a comma-expression.
You should also note that if the body of the temporary struct is made up of a char array, it may not have sufficient alignment to represent the incoming data correctly. From C11 onwards you should specify the alignment of the array with _Alignas:
struct {
_Alignas (max_align_t) unsigned char data[sizeof(SomeStruct)];
} a, *tmp;
...which will ensure it can safely store the data for any type regardless of alignment. In C99 you don't have any way to explicitly request max alignment, but you can force the alignment to match a named type by making the temporary struct a member of a union alongside it (you might try long double and hope that's the most-aligned type).
I found this code in a header file for a device that I need to use, and although I've been doing C for years, I've never run into this:
struct device {
};
struct spi_device {
struct device dev;
};
and it used as in:
int spi_write_then_read(struct spi_device *spi,
const unsigned char *txbuf, unsigned n_tx,
unsigned char *rxbuf, unsigned n_rx);
and also here:
struct spi_device *spi = phy->spi;
where it is defined the same.
I'm not sure what the point is with this definition. It is in a header file for a linux application of the board, but am baffled by it use. Any explanations, ideas? Anyone seen this before (I'm sure some of you have :).
Thanks!
:bp:
This is not C as C structures have to contain at least one named member:
(C11, 6.7.2.1 Structure and union specifiers p8) "If the struct-declaration-list does not contain any named members, either directly or via an anonymous structure or anonymous union, the behavior is undefined."
but a GNU C extension:
GCC permits a C structure to have no members:
struct empty {
};
The structure has size zero
https://gcc.gnu.org/onlinedocs/gcc/Empty-Structures.html
I don't know what is the purpose of this construct in your example but in general I think it may be used as a forward declaration of the structure type. Note that in C++ it is allowed to have a class with no member.
In Linux 2.4 there is an example of an empty structure type with conditional compilation in the definition of spin_lock_t type alias in Linux kernel 2.4 (in include/linux/spinlock.h):
#if (DEBUG_SPINLOCKS < 1)
/* ... */
typedef struct { } spinlock_t;
#elif (DEBUG_SPINLOCKS < 2)
/* ... */
typedef struct {
volatile unsigned long lock;
} spinlock_t;
#else /* (DEBUG_SPINLOCKS >= 2) */
/* ... */
typedef struct {
volatile unsigned long lock;
volatile unsigned int babble;
const char *module;
} spinlock_t;
#endif
The purpose is to save some space without having to change the functions API in case DEBUG_SPINLOCKS < 1. It also allows to define dummy (zero-sized) objects of type spinlock_t.
Another example in the (recent) Linux kernel of an empty structure hack used with conditional compilation in include/linux/device.h:
struct acpi_dev_node {
#ifdef CONFIG_ACPI
void *handle;
#endif
};
See the discussion with Greg Kroah-Hartman for this last example here:
https://lkml.org/lkml/2012/11/19/453
This is not standard C.
C11: 6.2.5-20:
— A structure type describes a sequentially allocated nonempty set of member objects (and, in certain circumstances, an incomplete array), each of which has an optionally specified name and possibly distinct type.
J.2 Undefined behavior:
The behavior is undefined in the following circumstances:
....
— A structure or union is defined without any named members (including those
specified indirectly via anonymous structures and unions) (6.7.2.1).
GCC uses it as an extension (no more detailed is given there about when/where should it be used). Using this in any program will make it compiler specific.
One reason might to do this for a library is that the library developers do not want you to know or interfere with the internals of these struct. It these cases they may provide an "interface" version of the structs spi_device/device (which is what you may see) and have a second type definition that defines another version of said structs for use inside the library with the actual members.
Since you cannot access struct members or even create compatible structs of that type yourself with that approach (since even your compiler would not know the size actual size of this struct), this only works if the library itself creates the structs, only ever passes you pointers to it, and does not need you to modify any members.
If you add an empty struct as the first member of another struct, the empty
struct can serve as a "marker interface", i.e. when you cast a pointer to that
outer struct to a pointer of the inner struct and the cast succeeds you know
that the outer struct is "marked" as something.
Also it might just be a place holder for future development, not to sure. Hope this helps
This is valid C
struct empty;
struct empty *empty;
and facilitates use of addresses of opaque regions of memory.
Such addresses are usually obtained from and passed to library subroutines.
For example, something like this is done in stdio.h
I'm trying to initialise a structure which ends with an array[0] (here, char iedata[0]) for the actual packet payload. If I try to initialise it inline, like this:
struct some_packet pkt = {
.elem1 = blah, .elem2 = bleh,
.iedata = {
1, 2, 3, 4
}
};
I get a warning from gcc:
warning: (near initialization for ‘pkt.iedata’)
Is there any good way to mark that this is a proper initialisation?
If you're able to compile in C99 mode, you could try using standard flexible length arrays rather than the zero-length hack: http://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
Note that in GCC 3.0 and newer, extra entries in an array initialiser will be discarded (per the documentation linked above).
As you are using C99 initialization, why not make the member a proper FAM, i.e. char data[];
The only way to create valid struct's with a FAM (or struct hack member) is by dynamically allocating the correct amount of excess storage for the last member so, as the warning suggests, your local initialization isn't valid.