Reputation: 473
Given the following code:
RTIME *rtCreate(void)
{
RTIME *rtime;
rtime = malloc(sizeof(*rtime));
if (rtime != NULL)
{
/* Initialization stuff */
}
return rtime;
}
void rtDestroy(RTIME **rtime)
{
if (*rtime != NULL)
{
free(*rtime);
*rtime = NULL;
}
}
what would cause GCC to complain that "passing argument 1 of 'free' discards qualifiers from pointer target type"? I understood that it was unnecessary to cast the result of malloc (as discussed here), as the pointer to void is automagically converted to the correct type. Why then does the compiler seem to be implying that I must cast *rtime
before it may be freed?
EDIT:- RTIME is defined as follows.
typedef struct RTIME
{
uint8 Sec;
uint8 Min;
uint8 Hour;
uint8 DayOfWeek;
uint8 DayOfMonth;
uint16 DayOfYear;
uint8 Month;
uint16 Year;
} volatile RTIME;
Upvotes: 0
Views: 1207
Reputation: 16441
The problem is with the volatile
attribute - free
gets void *
, which isn't volatile, so you can't pass RTIME
(which is volatile) to it.
You should ask yourself why you're using volatile
at all. This qualifier is often misunderstood.
In many cases I've seen, volatile
is used either to solve a non-existing problem, or a problem that still exist even if you use it (most often race conditions).
Upvotes: 0
Reputation: 753930
Taking your code and making an SSCCE from it, like so:
#include <stdlib.h>
struct RTIME { int a; int b; };
typedef const struct RTIME RTIME;
RTIME *rtCreate(void)
{
RTIME *rtime;
rtime = malloc(sizeof(*rtime));
if (rtime != NULL)
{
/* Initialization stuff */
}
return rtime;
}
void rtDestroy(RTIME **rtime)
{
if (*rtime != NULL)
{
free(*rtime);
*rtime = NULL;
}
}
Compiling with GCC 4.7.1 and the command line:
$ gcc -O3 -g -std=c99 -Wall -Wextra -Wmissing-prototypes -c mf.c
mf.c:6:8: warning: no previous prototype for ‘rtCreate’ [-Wmissing-prototypes]
mf.c:20:6: warning: no previous prototype for ‘rtDestroy’ [-Wmissing-prototypes]
mf.c: In function ‘rtDestroy’:
mf.c:24:9: warning: passing argument 1 of ‘free’ discards ‘const’ qualifier from pointer target type [enabled by default]
In file included from mf.c:1:0:
/usr/include/stdlib.h:160:7: note: expected ‘void *’ but argument is of type ‘const struct RTIME *’
$
Omit the const
and you only get the (valid) warnings about the missing prototypes.
I'm guessing you're using an older version of GCC (because older versions don't include the extra information in the note:
line), and that somehow or other your typedef
for RTIME
includes a const
.
As a general rule, you don't want const
in a typedef
, but there are bound to be exceptions to the rule.
It turns out from the edited question that the qualifier was volatile
rather than const
. When the typedef
in my sample code is changed, GCC 4.7.1 says:
mf.c:6:8: warning: no previous prototype for ‘rtCreate’ [-Wmissing-prototypes]
mf.c:20:6: warning: no previous prototype for ‘rtDestroy’ [-Wmissing-prototypes]
mf.c: In function ‘rtDestroy’:
mf.c:24:9: warning: passing argument 1 of ‘free’ discards ‘volatile’ qualifier from pointer target type [enabled by default]
In file included from mf.c:1:0:
/usr/include/stdlib.h:160:7: note: expected ‘void *’ but argument is of type ‘volatile struct RTIME *’
When I compile with the system GCC, I get a simpler, less precise error message:
mf.c:7: warning: no previous prototype for ‘rtCreate’
mf.c:21: warning: no previous prototype for ‘rtDestroy’
mf.c: In function ‘rtDestroy’:
mf.c:24: warning: passing argument 1 of ‘free’ discards qualifiers from pointer target type
This is from Apple's GCC:
i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.11.00)
So, the qualifier was volatile
rather than const
.
One good reason to try to upgrade to GCC 4.7.x is that the error messages are much improved over earlier versions. The improved messages are also in 4.6.0; the messages in 4.5.2 were the older style, less informative messages.
Upvotes: 1
Reputation: 17593
I suggest that you rewrite your rtDestroy()
function as follows. It appears the GCC is seeing the dereference of a pointer to a pointer and sees that as a source of possible error.
It appears that you are wanting to free the memory allocated and to then set the pointer to NULL in order to easily detect that the pointer is no longer valid. However by doing what you are doing, the free()
function is being given the address of the memory to free through a redirection which the compiler is unable to check.
So if you assign the address that is pointed to by *rtime to a local variable and then pass that into the free() function, the compiler check should pass. This seems to be a fairly common warning with some types of source constructs. It seems to be most common when a const modifier is needed on a variable and it is not specified. See this example Initialization discards qualifiers from pointer target type.
void rtDestroy(RTIME **rtime)
{
RTIME *pTemp = *rtime;
if (*rtime != NULL)
{
free(pTemp);
*rtime = NULL;
}
}
EDIT: It appears that RTIME is a variable type containing hardware time tick in nanoseconds or something like that. Not sure why it would be const unless the functions used provide a pointer to an operating system memory area that is read only.
I suggest that there is no real need to do the allocation of memory that instead you would use a variable on the stack and use the appropriate function to retrieve the current value which will be changing anyway.
However rather than using RTIME *pTemp = *rtime;
you could try to use void *pTemp = (void *) (*rtime);
however if RTIME involves a const then I expect this will just put the warning to that line instead. Jonathan Leffler (see comment below) reports he sees the same error with the change I suggested above.
See this article Real Time Linux II.
Upvotes: 0