Hi trying to port some code and I'm not understanding the problem here,
getting the error - file.c:370:17: error: variable has incomplete type 'struct stat'
here is the code that is throwing up the error
int srcfd, destfd;
int nread;
char ifc[PROPERTY_VALUE_MAX];
char *pbuf;
char *sptr;
struct stat sb;
if (stat(config_file, &sb) != 0)
return -1;
pbuf = malloc(sb.st_size + PROPERTY_VALUE_MAX);
if (!pbuf)
return 0;
i've read various stackoverflow questions regarding incomplete types and defining in header files, but i don't understand how to implement any of that. i've tried moving the function about, declaring it in a header file and outside the function . but get the same error.
The structure struct stat is only declared but not defined.
struct stat sb;
So the compiler does not know how much memory an object of the structure type will require and whether indeed the structure has for example the data member st_size used in this statement
pbuf = malloc(sb.st_size + PROPERTY_VALUE_MAX);
^^^^^^^^^^
If the structure is defined in some header then you need to include the header in this translation unit.
Related
I am using a library which contains the following declaration in its header (http_client.h):
typedef struct _httpc_state httpc_state_t;
The library defines the struct in the implementation (http_client.c)
typedef struct _httpc_state
{
struct altcp_pcb* pcb;
ip_addr_t remote_addr;
u16_t remote_port;
int timeout_ticks;
struct pbuf *request;
struct pbuf *rx_hdrs;
u16_t rx_http_version;
u16_t rx_status;
altcp_recv_fn recv_fn;
const httpc_connection_t *conn_settings;
void* callback_arg;
u32_t rx_content_len;
u32_t hdr_content_len;
httpc_parse_state_t parse_state;
#if HTTPC_DEBUG_REQUEST
char* server_name;
char* uri;
#endif
} httpc_state_t;
In that same C file, it implements the following function, which uses the struct:
/** http client tcp poll callback */
static err_t
httpc_tcp_poll(void *arg, struct altcp_pcb *pcb)
{
/* implement timeout */
httpc_state_t* req = (httpc_state_t*)arg; // Here the void pointer is casted to httpc_state_t
LWIP_UNUSED_ARG(pcb);
if (req != NULL) {
if (req->timeout_ticks) { // Here the concrete type is used. Works. No problems.
req->timeout_ticks--;
}
if (!req->timeout_ticks) {
return httpc_close(req, HTTPC_RESULT_ERR_TIMEOUT, 0, ERR_OK);
}
}
return ERR_OK;
}
I have a C++ file which uses this library, and of course includes the required header (http_client.h).
extern "C"
{
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"
#include "lwip/tcpip.h"
#include "lwip/apps/http_client.h" // Here I include their http_client.h file
#include "projdefs.h"
}
In my next function, I need to do exactly what their implementation does. I need to do something with httpc_state_t. I implemented their callback function as follows:
err_t rec_fn(void *arg, struct altcp_pcb *conn, struct pbuf *p, err_t err)
{
if (p)
{
httpc_state_t* req = (httpc_state_t*)arg; // Compiler sees no problems in casting to my desired type....
req->timeout_ticks = 30; // COMPILE ERROR, pointer to incomplete class type _httpc_state is not allowed
}
}
Why am I getting that compile error?! Header file is included. Header files declares the typedef. Even after reading this and this, I still don't see what I am doing wrong....
In the translation unit where the function rec_fn is defined the compiler sees only the following declaration
typedef struct _httpc_state httpc_state_t;
It knows nothing about whether the data member timeout_ticks used in this statement
req->timeout_ticks = 30;
is indeed declared within the structure struct _httpc_state and what is its type. That is the name timeout_ticks is undeclared in this translation unit. So the compiler issues an error.
If you are going to use data members of the structure in a translation unit then the compiler needs to know their declarations. That is you need also to include the structure definition.
Either move the structure definition in the header if you are allowed to do that or duplicate its definition in the module where your function is defined.
Pay attention to that if the structure definition was not placed in the header then the reason of that can be that the author of the code does not want to make it available outside his module or library.
Incomplete type means its declared but not defined. You need to define that struct in the header file and include it into your C file.
The error message is poorly worded.
Pointers to incomplete types are fine!
Dereferencing to a member of an incomplete type is the problem.
At the point where the error occurs the compiler hasn't 'seen' the full definition of the type in that translation unit.
It recognises the type, but doesn't know if the type even has a member timeout_ticks let alone how to generate code for access it.
[Such as where the member is in relation to the start of the object.]
Pointers to incomplete types are a useful way to reduce dependencies and code coupling. If code only needs to pass pointers to a type around the type can be declared (incomplete) and help with type checking but not be exposed to the full definition.
I have defined these structures.
struct http_req {
struct http_req_line rl;
}
struct http_req_line {
enum method {
OPTIONS,
GET,
HEAD,
POST,
PUT,
DELETE,
TRACE,
CONNECT
} method;
enum uri_type {
ASTERISK,
ABSOLUTEURI,
ABS_PATH,
AUTHORITY
} uri_type;
union req_uri {
char asterisk[1];
char absoluteURI[256];
char abs_path[256];
char authority[256];
} req_uri;
char http_ver[16];
};
When I compile the file this header file is included in (which compiles fine on its own), gcc gives me this
request_types.h:2:23: error: field ‘rl’ has incomplete type
struct http_req_line rl;
But changing the 2nd line of the header to
struct http_req_line *rl;
gets rid of this error. What causes this error, and does changing that member to a pointer really fix the problem, or just hide it from the compiler?
At the point where the compiler sees:
struct http_req {
struct http_req_line rl;
}
there is no information about what a struct http_req_line is. You need the structure definition for struct http_req to appear after the definition of struct http_req_line. You can use a pointer (to an incomplete type); you can't use a copy of the structure.
See the C11 standard §6.7.2.1 Structure and union specifiers:
A structure or union shall not contain a member with incomplete or function type (hence, a structure shall not contain an instance of itself, but may contain a pointer to an instance of itself), …
At the point where you are defining struct http_req, struct http_req_line is not known. The compiler does not know how big it is or what its alignment requirement is, so it does not know how much space to use for the rl member and cannot complete its definition of struct http_req.
If you want to embed a struct http_req_line inside a struct http_req, move the definition of struct http_req_line before the definition of struct http_req.
If you change rl to be a pointer, the type is not incomplete in the C sense because the compiler will know how big the pointer is and what its alignment requirement is. It does not need to know how big the structure it points to is in order to be able to plan space for the pointer rl.
You're seeing this error because you're attempting to define an instance of a struct before the struct itself has been defined. You need to define it first, then use it:
struct http_req_line {
enum method {
OPTIONS,
GET,
HEAD,
POST,
PUT,
DELETE,
TRACE,
CONNECT
} method;
enum uri_type {
ASTERISK,
ABSOLUTEURI,
ABS_PATH,
AUTHORITY
} uri_type;
union req_uri {
char asterisk[1];
char absoluteURI[256];
char abs_path[256];
char authority[256];
} req_uri;
char http_ver[16];
};
struct http_req {
struct http_req_line rl;
};
The reason that changing the member type to a pointer works is because you don't need to have the full struct definition to use a pointer to it. When the type definition is needed is when that pointer would be dereferenced.
I'm fairly new to C and am starting to learn header files. Whilst using my header I'm getting an error saying invalid type argument of '->' (have struct dirent). I don't understand what this means, I read here that the second argument to -> must be a pointer, so I tried to add a * to it (ent->*d_name) however then I get the error unexpected token *, how can I fix this?
#ifndef UTILIS_H_INCLUDED
#define UTILIS_H_INCLUDED "utilis.h"
#include <stdio.h>
#include <dirent.h>
char *connect(const char *pattern)
{
struct dirent ent;
char *d_name;
DIR *mgt = opendir("\\\\example\\windows7apps");
while ((ent = readdir(mgt)) != pattern)
{
puts(ent->d_name);
}
}
#endif
I read here that the second argument to -> must be a pointer,
That's wrong, the "first" argument, or, actually, the operand of the -> operator should be of pointer type.
In your case, ent is not a pointer type, so you cannot use the pointer member dereference operator ->. (you could have used the member dereference operator . instead).
Actually, in your code, ent should be a pointer, as per the return type of readdir(). So you better correct the type of ent to be of struct dirent *, then you can make use of -> on ent.
usually header files only contain data definitions and function prototypes. Your function definition should almost certainly be in a C file.
If you look at the function readdir it returns a pointer to a struct dirent so your variable ent should be a pointer
struct dirent *readdir(DIR *dirp);
struct dirent *ent;
That will fix your error invalid type argument of '->' (have struct dirent)
I'm trying to use the st_mode from a returned stat struct, that I get from the stat() call following way;
char *fn = "test.c"
struct stat *buf = malloc(sizeof(stat));
stat(fn,buf);
if(S_ISREG(buf.st_mode))
{
printf("this file is a regular file..."); //if regular
}
When I try to compile this code, I get the following error:
server1.c: In function ‘main’:
server1.c:223:32: error: request for member ‘st_mode’ in something not
a structure or union
if(S_ISREG(fileData.st_mode))
^
Why do I get this compile error? I can't seem to find much info myself..
buf is not a struct stat. buf is a pointer to a struct stat, and pointers don't have st_mode fields. To get the st_mode field of the struct stat that buf points to, use (*buf).st_mode, or buf->st_mode for short.
I have a function and a struct defined in my library. I want the function to return a pointer to the struct. When I try to compile the program and the library I get the following error:
error: incomplete definition of type 'struct _bmpfile'
printf("file size: %d", bmp->header.filesz);
~~~^
/usr/local/include/bmpfile.h:116:16: note: forward declaration of 'struct _bmpfile'
typedef struct _bmpfile bmpfile_t;
The struct is declared in bmpfile.h and then defined in bmpfile.c. My program, main.c, calls the following function which should return a bmpfile_t:
bmp = bmp_create_from_file(filename);
bmpfile_t*
bmp_create_from_file(const char *filename)
{
FILE *fp;
fp = fopen(filename, "r");
if (fp == NULL) perror("error");
bmpfile_t *bmp = (bmpfile_t *)malloc(sizeof(bmpfile_t));
bmp_get_header_from_file(fp, bmp);
bmp_get_dib_from_file(fp, bmp);
bmp_get_pixels_from_file(fp, bmp);
fclose(fp);
return bmp;
}
That printf call will need a full definition of the struct before it can access the members.
It's common for libraries to declare only the name of the struct in the header file, so files including the header can manipulate pointers to the type without knowing the contents. The struct is considered opaque. This is roughly the C equivalent to declaring all members private.
For hacking purposes, you can paste the structure definition into your main file and peek at the values in the struct. But for "production" code, don't ever do this, period, end-of-sentence (unless you have a really really really good reason, but be prepared to explain this reason to anyone who may see the code!).
As paulsm4 says, you can use bmp_header_t bmp_get_header(bmpfile_t *bmp); to get a header object that you can access.
The problem is that bmpfile_t is declared as an "opaque struct".
Solution: simply call bmp_get_header()