How to fix compiler warning

D

Dave Stafford

I have a macro that I use across the board for freeing ram. I'd like to
clean up my code so I don't get these warnings.

#define sfree(x) _internal_sfree((void **)&x)
#define _internal_sfree(x) ({ if(x && *x) { free(*x); *x=NULL; } })

void main() {
char *x = (char *) malloc(10);
int *y = (int *) malloc(10);

sfree(x);
sfree(y);
}

results in:

warning: dereferencing type-punned pointer will break strict-aliasing
rules
 
I

Ian Collins

Dave said:
I have a macro that I use across the board for freeing ram. I'd like to
clean up my code so I don't get these warnings.

#define sfree(x) _internal_sfree((void **)&x)
#define _internal_sfree(x) ({ if(x && *x) { free(*x); *x=NULL; } })
Remove the extraneous parenthesis around the expression.
void main() {

If you didn't get a warning for this, crank up the warning level!
 
I

Ian Collins

Ian said:
Remove the extraneous parenthesis around the expression.
Which still leaves the question why cast to void** and why test for NULL?

How about:

#define sfree(x) _internal_sfree(&x)
#define _internal_sfree(x) { free(*x); *x=NULL; }
 
K

Keith Thompson

Dave Stafford said:
I have a macro that I use across the board for freeing ram. I'd like to
clean up my code so I don't get these warnings.

#define sfree(x) _internal_sfree((void **)&x)
#define _internal_sfree(x) ({ if(x && *x) { free(*x); *x=NULL; } })

void main() {
char *x = (char *) malloc(10);
int *y = (int *) malloc(10);

sfree(x);
sfree(y);
}

results in:

warning: dereferencing type-punned pointer will break strict-aliasing
rules

Your macro depends on a gcc-specific extension (see "Statement Exprs"
in the gcc manual).

You take care to avoid passing a null pointer to free(), but
free(NULL) is guaranteed to do nothing.

Take a look at the following version of your program.
================================
#include <stdlib.h>

#define SFREE(p) (free(p), (p) = NULL)

int main(void) {
char *x = malloc(10);
int *y = malloc(10 * sizeof *y);

SFREE(x);
SFREE(y);
return 0;
}
================================

Every change I made fixes a bug in your code:

main() returns int, not void. And since it returns int, you should
return an int.

I renamed the macro from "sfree" to "SFREE"; by convention, most
macros should have all-caps names.

In a macro definition, references to arguments should be enclosed in
parentheses to avoid operator precedence problems.

Casting the result of malloc() is useless, and can hide bugs.

You didn't have a '#include <stdlib.h>'. This is required if you're
going to call malloc(). The casts probably silenced your compiler's
warning about this, but didn't fix the bug (it's like snipping the
wire to a warning light on your car's dashboard).

Allocating 10 bytes for an int* doesn't make much sense if, for
example, sizeof(int) == 4. I changed it to allocate 10 ints.

Recommended reading: the comp.lang.c FAQ, <http://www.c-faq.com/>.
 
P

Philip Potter

Ian said:
Which still leaves the question why cast to void** and why test for NULL?

How about:

#define sfree(x) _internal_sfree(&x)
#define _internal_sfree(x) { free(*x); *x=NULL; }

Surely you should check that x!=NULL before calling *any* function on *x?
 
M

Martin Ambuhl

Dave said:
I have a macro that I use across the board for freeing ram. I'd like to
clean up my code so I don't get these warnings.

What about those diagnostics you _should_ have gotten, but either didn't
get or forgot to tell us about?

You seem to have already taken the first step toward getting rid of the
diagnostics: you have set your diagnostic level too low. Lower it again
and maybe it will compile Fortran as C without complaint.
 
B

Ben Bacarisse

Philip Potter said:
Surely you should check that x!=NULL before calling *any* function
on *x?

That is not really a problem -- the x in _internal_sfree is always of
the form &... [Obviously this is only true if it is not invoked
directly, but there is no practical way to avoid problems if internal
helper macros are invoked by user code.]

Since the x is of the form &... and * and & "cancel each other out"
(talking very loosely) you end up not needing the other macro. With
the required extra parentheses, a comma expression rather than a
block, and a better name you get Keith's version:

#define SFREE(p) (free(p), (p) = NULL)
 
P

Philip Potter

Ben said:
Philip Potter said:
Surely you should check that x!=NULL before calling *any* function
on *x?

That is not really a problem -- the x in _internal_sfree is always of
the form &... [Obviously this is only true if it is not invoked
directly, but there is no practical way to avoid problems if internal
helper macros are invoked by user code.]

Yes of course, I should have seen that before!
 
I

Ian Collins

Philip said:
Ben said:
Philip Potter said:
Ian Collins wrote:
Which still leaves the question why cast to void** and why test for
NULL?

How about:

#define sfree(x) _internal_sfree(&x)
#define _internal_sfree(x) { free(*x); *x=NULL; }
Surely you should check that x!=NULL before calling *any* function
on *x?

That is not really a problem -- the x in _internal_sfree is always of
the form &... [Obviously this is only true if it is not invoked
directly, but there is no practical way to avoid problems if internal
helper macros are invoked by user code.]

Yes of course, I should have seen that before!
See what happens when "function like" macros have lower case names :)
 
P

Philip Potter

Ian said:
Philip said:
Ben said:
Ian Collins wrote:
Which still leaves the question why cast to void** and why test for
NULL?

How about:

#define sfree(x) _internal_sfree(&x)
#define _internal_sfree(x) { free(*x); *x=NULL; }
Surely you should check that x!=NULL before calling *any* function
on *x?
That is not really a problem -- the x in _internal_sfree is always of
the form &... [Obviously this is only true if it is not invoked
directly, but there is no practical way to avoid problems if internal
helper macros are invoked by user code.]
Yes of course, I should have seen that before!
See what happens when "function like" macros have lower case names :)
How would it be any different if they were real functions?
 
K

Keith Thompson

Philip Potter said:
Ian said:
Philip said:
Ben Bacarisse wrote:

Ian Collins wrote:
Which still leaves the question why cast to void** and why test for
NULL?

How about:

#define sfree(x) _internal_sfree(&x)
#define _internal_sfree(x) { free(*x); *x=NULL; }
Surely you should check that x!=NULL before calling *any* function
on *x?
That is not really a problem -- the x in _internal_sfree is always of
the form &... [Obviously this is only true if it is not invoked
directly, but there is no practical way to avoid problems if internal
helper macros are invoked by user code.]
Yes of course, I should have seen that before!
See what happens when "function like" macros have lower case names :)
How would it be any different if they were real functions?

The sfree() macro takes the address of its argument. If a function
did that, it would get the address of the parameter, a local object,
not the address of the object you pass to it.
 
R

Richard Heathfield

Ian Collins said:
If you didn't get a warning for this, crank up the warning level!

Whilst it's wrong (except on some freestanding implementations), it
isn't a syntax error or a constraint violation. Implementations need
not diagnose it (although some choose to do so).
 
P

pete

Richard said:
Ian Collins said:


Whilst it's wrong (except on some freestanding implementations), it
isn't a syntax error or a constraint violation. Implementations need
not diagnose it (although some choose to do so).

I don't see void main() as being as more or less correct
on freestanding implementations which define void main(),
than it is on hosted implementations which define void main().
 
I

Ian Collins

pete said:
I don't see void main() as being as more or less correct
on freestanding implementations which define void main(),
than it is on hosted implementations which define void main().
Section 5.1.2.2.1 of the standard does.
 
R

Richard Heathfield

pete said:
I don't see void main() as being as more or less correct
on freestanding implementations which define void main(),
than it is on hosted implementations which define void main().

In C90, it's wrong on hosted implementations. Freestanding
implementations are free to insist on their own entry point syntax if
they wish, but C90 implementations must provide int main(int, char **)
and correct C90 programs must use int main(int char **) - not to do so
renders the behaviour of the program undefined.

In C99, the situation has not changed in the freestanding world - and,
in practice, it hasn't actually changed in the hosted world either,
since implementations were always free to document alternate entry
point syntax. The only difference is academic - in C99, if your program
takes advantage of an implementation's documented alternative, your
program's behaviour *under that implementation* is
implementation-defined rather than undefined. If you try to port it,
however, this academic distinction vanishes, and you're right back to
undefined behaviour again. That change was one of C99's grosser
stupidities.
 
C

Christopher Benson-Manica

[comp.lang.c] Richard Heathfield said:
Ian Collins said:
If you didn't get a warning for this, crank up the warning level!
Whilst it's wrong (except on some freestanding implementations), it
isn't a syntax error or a constraint violation. Implementations need
not diagnose it (although some choose to do so).

I would think that an implementation worth its salt would provide a
warning level at which it did issue a diagnostic for void main(). Are
there any major implementations which cannot be coerced into doing so?
 
R

Richard Heathfield

Christopher Benson-Manica said:
[comp.lang.c] Richard Heathfield said:
Ian Collins said:
If you didn't get a warning for this, crank up the warning level!
Whilst it's wrong (except on some freestanding implementations), it
isn't a syntax error or a constraint violation. Implementations need
not diagnose it (although some choose to do so).

I would think that an implementation worth its salt would provide a
warning level at which it did issue a diagnostic for void main(). Are
there any major implementations which cannot be coerced into doing so?

Borland can, and gcc can. Last time I checked, which was VS6, Microsoft
couldn't.
 
F

Francine.Neary

pete said:





In C90, it's wrong on hosted implementations. Freestanding
implementations are free to insist on their own entry point syntax if
they wish, but C90 implementations must provide int main(int, char **)
and correct C90 programs must use int main(int char **) - not to do so
renders the behaviour of the program undefined.

I believe you are mistaken - in both C90 and C99, main can also take
no parameters. (It must still return an int of course.)
 
R

Richard Heathfield

(e-mail address removed) said:
[...] C90 implementations must provide int main(int, char
**) and correct C90 programs must use int main(int char **) - not to
do so renders the behaviour of the program undefined.

I believe you are mistaken - in both C90 and C99, main can also take
no parameters. (It must still return an int of course.)

Whoops! Yes, of course it can instead take no parameters. Would you
believe me if I told you I knew that really? :)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,580
Members
45,055
Latest member
SlimSparkKetoACVReview

Latest Threads

Top