Now before people start marking this a dup, I've read all the following, none of which provide the answer I'm looking for:
C FAQ: What's wrong with casting malloc's return value?
SO: Should I explicitly cast malloc()’s return value?
SO: Needless pointer-casts in C
SO: Do I cast the result of malloc?
Both the C FAQ and many answers to the above questions cite a mysterious error that casting malloc's return value can hide; however, none of them give a specific example of such an error in practice. Now pay attention that I said error, not warning.
Now given the following code:
#include <string.h>
#include <stdio.h>
// #include <stdlib.h>
int main(int argc, char** argv) {
char * p = /*(char*)*/malloc(10);
strcpy(p, "hello");
printf("%s\n", p);
return 0;
}
Compiling the above code with gcc 4.2, with and without the cast gives the same warnings, and the program executes properly and provides the same results in both cases.
anon#anon:~/$ gcc -Wextra nostdlib_malloc.c -o nostdlib_malloc
nostdlib_malloc.c: In function ‘main’:
nostdlib_malloc.c:7: warning: incompatible implicit declaration of built-in function ‘malloc’
anon#anon:~/$ ./nostdlib_malloc
hello
So can anyone give a specific code example of a compile or runtime error that could occur because of casting malloc's return value, or is this just an urban legend?
Edit I've come across two well written arguments regarding this issue:
In Favor of Casting: CERT Advisory: Immediately cast the result of a memory allocation function call into a pointer to the allocated type
Against Casting (404 error as of 2012-02-14: use the Internet Archive Wayback Machine copy from 2010-01-27.{2016-03-18:"Page cannot be crawled or displayed due to robots.txt."})
You won't get a compiler error, but a compiler warning. As the sources you cite say (especially the first one), you can get an unpredictable runtime error when using the cast without including stdlib.h.
So the error on your side is not the cast, but forgetting to include stdlib.h. Compilers may assume that malloc is a function returning int, therefore converting the void* pointer actually returned by malloc to int and then to your pointer type due to the explicit cast. On some platforms, int and pointers may take up different numbers of bytes, so the type conversions may lead to data corruption.
Fortunately, modern compilers give warnings that point to your actual error. See the gcc output you supplied: It warns you that the implicit declaration (int malloc(int)) is incompatible to the built-in malloc. So gcc seems to know malloc even without stdlib.h.
Leaving out the cast to prevent this error is mostly the same reasoning as writing
if (0 == my_var)
instead of
if (my_var == 0)
since the latter could lead to a serious bug if one would confuse = and ==, whereas the first one would lead to a compile error. I personally prefer the latter style since it better reflects my intention and I don't tend to do this mistake.
The same is true for casting the value returned by malloc: I prefer being explicit in programming and I generally double-check to include the header files for all functions I use.
One of the good higher-level arguments against casting the result of malloc is often left unmentioned, even though, in my opinion, it is more important than the well-known lower-level issues (like truncating the pointer when the declaration is missing).
A good programming practice is to write code, which is as type-independent as possible. This means, in particular, that type names should be mentioned in the code as little as possible or best not mentioned at all. This applies to casts (avoid unnecessary casts), types as arguments of sizeof (avoid using type names in sizeof) and, generally, all other references to type names.
Type names belong in declarations. As much as possible, type names should be restricted to declarations and only to declarations.
From this point of view, this bit of code is bad
int *p;
...
p = (int*) malloc(n * sizeof(int));
and this is much better
int *p;
...
p = malloc(n * sizeof *p);
not simply because it "doesn't cast the result of malloc", but rather because it is type-independent (or type-agnositic, if you prefer), because it automatically adjusts itself to whatever type p is declared with, without requiring any intervention from the user.
Non-prototyped functions are assumed to return int.
So you're casting an int to a pointer. If pointers are wider than ints on your platform, this is highly risky behavior.
Plus, of course, that some people consider warnings to be errors, i.e. code should compile without them.
Personally, I think the fact that you don't need to cast void * to another pointer type is a feature in C, and consider code that does to be broken.
If you do this when compiling in 64-bit mode, your returned pointer will be truncated to 32-bits.
EDIT:
Sorry for being too brief. Here's an example code fragment for discussion purposes.
main()
{
char * c = (char *)malloc(2) ;
printf("%p", c) ;
}
Suppose that the returned heap pointer is something bigger than what is representable in an int, say 0xAB00000000.
If malloc is not prototyped to return a pointer, the int value returned will initially be in some register with all the significant bits set. Now the compiler say, "okay, how do I convert and int to a pointer". That's going to be either a sign extension or zero extension of the low order 32-bits that it has been told malloc "returns" by omitting the prototype. Since int is signed I think the conversion will be sign extension, which will in this case convert the value to zero. With a return value of 0xABF0000000 you'll get a non-zero pointer that will also cause some fun when you try to dereference it.
A Reusable Software Rule:
In the case of writing an inline function in which used malloc(), in order to make it reusable for C++ code too, please do an explicit type casting (e.g. (char*)); otherwise compiler will complain.
A void pointer in C can be assigned to any pointer without an explicit cast. The compiler will give warning but it can be reusable in C++ by type casting malloc() to corresponding type. With out type casting also it can be use in C, because C is no strict type checking. But C++ is strictly type checking so it is needed to type cast malloc() in C++.
The malloc() function could often require a conversion cast before.
For the returned type from malloc it is a pointer to void and not a particular type, like may be a char* array, or a string.
And sometimes the compiler could not know, how to convert this type.
int size = 10;
char* pWord = (char*)malloc(size);
The allocation functions are available for all C packages.
So, these are general functions, that must work for more C types.
And the C++ libraries are extensions of the older C libraries.
Therefore the malloc function returns a generic void* pointer.
Cannot allocate an object of a type with another of different type.
Unless the objects are not classes derived from a common root class.
And not always this is possible, there are different exceptions.
Therefore a conversion cast might be necessary in this case.
Maybe the modern compilers know how to convert different types.
So this could not be a great issue, when is doing this conversion.
But a correct cast can be used, if a type conversion is possible.
As an example: it cannot be cast "apples" to "strawberries". But these both, so called "classes", can be converted to "fruits".
There are custom structure types, which cannot be cast directly.
In this case, any member variable has to be assigned separately.
Or a custom object would have to set its members independently.
Either if it is about a custom object class, or whatever else...
Also a cast to a void pointer must be used when using a free call.
This is because the argument of the free function is a void pointer.
free((void*)pWord);
Casts are not bad, they just don't work for all the variable types.
A conversion cast is also an operator function, that must be defined.
If this operator is not defined for a certain type, it may not work.
But not all the errors are because of this conversion cast operator.
With kind regards, Adrian Brinas
Related
static int* p= (int*)(&foo);
I just know p points to a memory in the code segment.
But I don't know what exactly happens in this line.
I thought maybe it's a pointer to a function but the format to point a function is:
returnType (*pointerName) (params,...);
pointerName = &someFunc; // or pointerName=someFunc;
You take the address of foo and cast it to pointer to int.
If foo and p are of different types, the compiler might issue a warning about type mismatch. The cast is to supress that warning.
For example, consider the following code, which causes a warning from the compiler (initialization from incompatible pointer type):
float foo = 42;
int *p = &foo;
Here foo is a float, while p points to an int. Clearly - different types.
A typecasting makes the compiler treat one variable as if it was of different type. You typecast by putting new type name in parenthesis. Here we will make pointer to float to be treated like a pointer to int and the warning will be no more:
float foo = 5;
int *p = (int*)(&foo);
You could've omitted one pair of parenthesis as well and it'd mean the same:
float foo = 5;
int *p = (int*)&foo;
The issue is the same if foo is a function. We have a pointer to a function on right side of assignment and a pointer to int on left side. A cast would be added to make a pointer to function to be treated as an address of int.
A pointer of a type which points to an object (i.e. not void* and not a
pointer to a function) cannot be stored to a pointer to any other kind of
object without a cast, except in a few cases where the types are identical
except for qualifiers. Conforming compilers are required to issue a
diagnostic if that rule is broken.
Beyond that, the Standard allows compilers to interpret code that casts
pointers in nonsensical fashion unless code aides by some restrictions
which, as written make such casts essentially useless, for the nominal
purpose of promoting optimization. When the rules were written, most
compilers would probably do about half of the optimizations that would
be allowed under the rules, but would still process pointer casts sensibly
since doing so would cost maybe 5% of the theoretically-possible
optimizations. Today, however, it is more fashionable for compiler writers
to seek out all cases where an optimization would be allowed by the
Standard without regard for whether they make sense.
Compilers like gcc have an option -fno-strict-aliasing that blocks this
kind of optimization, both in cases where it would offer big benefits and
little risk, as well as in the cases where it would almost certainly break
code and be unlikely to offer any real benefit. It would be helpful if they
had an option to block only the latter, but I'm unaware of one. Thus, my
recommendation is that unless one wants to program in a very limited subset
of Dennis Ritchie's language, I'd suggest targeting the -fno-strict-aliasing
dialect.
Hi after going through answer here
1: Do I cast the result of malloc? I understood that one of the reason why we do not cast malloc is that
casting malloc is redundant
But what I am still trying to figure out is the warning that will be suppressed when we do cast the malloc function
I also read this answer but I have the follwing doubts
#include<stdio.h>
main()
{
int *a=malloc(20);
}
I understood the point in the answer that compiler will think that malloc returns an int while we are trying to give that value to an int * which will gives us error cannot convert from int * to int or something like that but the basic question is
Won't the compiler in absence of stdlib.h treat malloc as a user defined function and wont it look for the declaration of it and it will give some error related to missing delcaration/defination
In the original C language - C89/90 - calling an undeclared function is not an error. For this reason, a pre-C99 compiler will not produce any "error" due to a missing function declaration. The compiler will simply assume that function returns an int.
It will also automatically and quietly "guess" (infer, derive) the function parameter types from the argument types you supplied in your call. In your example, you supplied 20, which will make the compiler to guess that the "unknown" malloc function takes a single parameter of type int. Note that this is also incorrect, because the real malloc takes a size_t parameter.
In C99 and later the function declaration is required. Which means that forgetting to declare malloc (e.g. forgetting to include <stdlib.h>) is indeed an error, which will result in a diagnostic message. (The parameter-guessing behavior is still there in the language though.)
Note also that in C99 and later declaring function main without an explicit return type int is illegal. The "implicit int" rule is specific to the original version of C language specification only. It no longer exists in C99 and later. You have to declare it as int main(... explicitly.
In the absence of stdlib.h the compiler thinks that the malloc() function will return int(For C89/90 and not from c99) and you are trying to assign that value to int * and hence there is a type mismatch and the compiler will report it
I'm on programming project 4 from chapter 19 of C programming, A Modern Approach. My code works but I get this warning trying to pass a function returning a void * parameter to printf with conversion specifier %s.
format %s expects argument of type char *, but argument 2 has type void * [-Wformat=]
I can easily get rid of the warning by casting the return type of the function to char *, like
printf("%s\n", (char *) function(param));
but I just want to know why this necessary since type void * is casted to another pointer type automatically.
Compiler is very right to complain in this case.
As per your logic itself, the function returning void * could return a structure pointer casted to void *, but then, %s won't be able to print that, isn't it?
So, if you know what you're doing, you can cast the result, for this case.
Also, as others pointed out, maybe it's worthy to mention that, this warning has nothing to do with the standard specification, as in the standards, there is no restriction of the type of the arguments. (Borrowing Mr. #WhozCraig's words) This warning is basically due to an additional layer of type-checking entirely performed by compiler on it's own, enabled by -Wformat flag in gcc .
As far as the pure language is concerned (not the standard library and its expectations, the actual formal language) you can push anything you want on that argument list (including something utterly incoherent in relating to the requirements of a %s format specifier of some library routine). Of course, unless whatever you pushed ultimately is, in fact, the address of a nullchar terminated sequence of char, printf itself will trapes into undefined behavior at your behest.
The warning you're receiving is based on an additional layer of api-checking within the compiler, not some violation of the language itself. That api checking is matching format specs with types of presented arguments for frequently-used standard library apis such as printf, scanf, etc. Could the author of that warning-check been a little more forgiving and ignore void* arguments for specs expecting pointer-types? Certainly, but the point of the check-feature would dwindle pretty rapidly were that the case. Consider this:
int a = 0;
void *b = &a;
printf("%s\n", b);
If that api-check feature is going to be worth any salt at all it had better bark about that mismatched type, because as far as the language itself is concerned, there is nothing wrong with this code. And that has nothing to do with what evil I just requested it do. As far as the language is concerned, printf is simply this:
int printf(char *format ...);
And the call I setup certainly fulfills that (bad for me, and thankfully, the api-checks of my modern compiler will let me know soon enough there may be a problem).
A pointer is a variable which points to a single memory location.
The number of bytes pointed by the pointer depends on the type of the pointer. So if it is int* then it is interpreted as 4 bytes,if it is a char* it is interpreted as 1 byte.
A void* has no type. So the compiler cant dereference this pointer. So in order for the compiler to understand the memory to be dereferenced we need typecasting here.
The printf function is declared as something like this:
int printf(char *format ...);
Here ... denotes any additional arguments the caller supplied (that is, your string you wanted to print). When printf examines these additional parameters, it uses some low-level code, which has no type safety.
This code cannot determine that the parameter has type void*, and cast it to char* automatically. Instead, if the binary representation of void* and char* is the same, the parameter can be extracted from the ... part without regard to its actual type. If the representation is different, the low-level code will try to print an incorrect value (and probably crash).
Representation of void* and char* is the same for all platforms that I know of, so it's probably safe (if you trust me, that is - please don't!). However, if you compile with gcc -Wall, as some people recommend, all warnings are upgraded to errors, so you should do the casting, as the compiler indicates.
For example, if I wanted to write a "free" that nulled the pointer, I could write something like:
void myfree(void **data) {
free(*data);
*data = NULL;
}
however, when I try to write this, I get a compiler warning (from gcc 4.6.2) saying: warning: passing argument 1 of ‘myfree’ from incompatible pointer type [enabled by default] ... note: expected ‘void **’ but argument is of type ‘char **‘ (in this case, I am freeing a char array).
It seems that void* is special cased to avoid this kind of warning, since calloc, free etc. don't trigger such warnings, but void** is not (given the above). Is the only solution an explicit cast, or have I misunderstood something?
[I am revisiting some pain points in a recent project, wondering how they could have been handled better, and so am poking at corner cases, hence the C questions today.]
update given that void* is special cased, I could hack around this using void* and casts inside myfree, but that would be a somewhat irresponsible solution because everyone and their dog are going to pass a pointer to something that looks like free, so I need some kind of compiler warning based on "degree of indirection" for this to be a practical solution. hence the idea of a generic "pointer to a pointer".
Technically, the standard allows different object pointer types to have different representations (even different sizes), although char* and void* are required have the same representation. But the following is UB:
int *ip = 0;
free(*(void**)(&ip));
simply because the memory for ip need not be the same size as the memory for a void*, and even if it is the bit pattern for a null pointer of type int* need not be the same as the bit pattern for a null pointer of type void*. If they're different, then of course the compiler has to insert code to convert between them whenever you convert an int* to void* or back.
In practice, implementations don't do that to you (and for example Posix forbids it).
More importantly though, the strict aliasing rules don't allow you to access a char* object using an lvalue of type void*. So in practice, concerns about pointer representation will not break your code, but the optimizer actually might. Basically, if the function call myfree((void**)(&p)) gets inlined, then the compiler might see:
char *p = <something>;
void **data = (void**)(&p);
free(*data);
*data = NULL;
// code that reads p
The optimizer is allowed to note that *data = NULL is setting an object of type void*, whereas the "code that reads p" is reading an object of type char*, which is forbidden from being aliased with that other, void* object over there. So it is allowed to reorder the instructions, eliminate *data = NULL; entirely, or possibly other things I haven't thought of that will ruin your day, but that would speed the code up if you hadn't broken the rules.
You can use the MACRO to do this operation. This will be really great compare to having a function; I hope you know the advantage of using MACRO.
#define FREE_IF_NOT_NULL(x) if (x != NULL) { \
free(x); \
x = NULL; \
}
Now before people start marking this a dup, I've read all the following, none of which provide the answer I'm looking for:
C FAQ: What's wrong with casting malloc's return value?
SO: Should I explicitly cast malloc()’s return value?
SO: Needless pointer-casts in C
SO: Do I cast the result of malloc?
Both the C FAQ and many answers to the above questions cite a mysterious error that casting malloc's return value can hide; however, none of them give a specific example of such an error in practice. Now pay attention that I said error, not warning.
Now given the following code:
#include <string.h>
#include <stdio.h>
// #include <stdlib.h>
int main(int argc, char** argv) {
char * p = /*(char*)*/malloc(10);
strcpy(p, "hello");
printf("%s\n", p);
return 0;
}
Compiling the above code with gcc 4.2, with and without the cast gives the same warnings, and the program executes properly and provides the same results in both cases.
anon#anon:~/$ gcc -Wextra nostdlib_malloc.c -o nostdlib_malloc
nostdlib_malloc.c: In function ‘main’:
nostdlib_malloc.c:7: warning: incompatible implicit declaration of built-in function ‘malloc’
anon#anon:~/$ ./nostdlib_malloc
hello
So can anyone give a specific code example of a compile or runtime error that could occur because of casting malloc's return value, or is this just an urban legend?
Edit I've come across two well written arguments regarding this issue:
In Favor of Casting: CERT Advisory: Immediately cast the result of a memory allocation function call into a pointer to the allocated type
Against Casting (404 error as of 2012-02-14: use the Internet Archive Wayback Machine copy from 2010-01-27.{2016-03-18:"Page cannot be crawled or displayed due to robots.txt."})
You won't get a compiler error, but a compiler warning. As the sources you cite say (especially the first one), you can get an unpredictable runtime error when using the cast without including stdlib.h.
So the error on your side is not the cast, but forgetting to include stdlib.h. Compilers may assume that malloc is a function returning int, therefore converting the void* pointer actually returned by malloc to int and then to your pointer type due to the explicit cast. On some platforms, int and pointers may take up different numbers of bytes, so the type conversions may lead to data corruption.
Fortunately, modern compilers give warnings that point to your actual error. See the gcc output you supplied: It warns you that the implicit declaration (int malloc(int)) is incompatible to the built-in malloc. So gcc seems to know malloc even without stdlib.h.
Leaving out the cast to prevent this error is mostly the same reasoning as writing
if (0 == my_var)
instead of
if (my_var == 0)
since the latter could lead to a serious bug if one would confuse = and ==, whereas the first one would lead to a compile error. I personally prefer the latter style since it better reflects my intention and I don't tend to do this mistake.
The same is true for casting the value returned by malloc: I prefer being explicit in programming and I generally double-check to include the header files for all functions I use.
One of the good higher-level arguments against casting the result of malloc is often left unmentioned, even though, in my opinion, it is more important than the well-known lower-level issues (like truncating the pointer when the declaration is missing).
A good programming practice is to write code, which is as type-independent as possible. This means, in particular, that type names should be mentioned in the code as little as possible or best not mentioned at all. This applies to casts (avoid unnecessary casts), types as arguments of sizeof (avoid using type names in sizeof) and, generally, all other references to type names.
Type names belong in declarations. As much as possible, type names should be restricted to declarations and only to declarations.
From this point of view, this bit of code is bad
int *p;
...
p = (int*) malloc(n * sizeof(int));
and this is much better
int *p;
...
p = malloc(n * sizeof *p);
not simply because it "doesn't cast the result of malloc", but rather because it is type-independent (or type-agnositic, if you prefer), because it automatically adjusts itself to whatever type p is declared with, without requiring any intervention from the user.
Non-prototyped functions are assumed to return int.
So you're casting an int to a pointer. If pointers are wider than ints on your platform, this is highly risky behavior.
Plus, of course, that some people consider warnings to be errors, i.e. code should compile without them.
Personally, I think the fact that you don't need to cast void * to another pointer type is a feature in C, and consider code that does to be broken.
If you do this when compiling in 64-bit mode, your returned pointer will be truncated to 32-bits.
EDIT:
Sorry for being too brief. Here's an example code fragment for discussion purposes.
main()
{
char * c = (char *)malloc(2) ;
printf("%p", c) ;
}
Suppose that the returned heap pointer is something bigger than what is representable in an int, say 0xAB00000000.
If malloc is not prototyped to return a pointer, the int value returned will initially be in some register with all the significant bits set. Now the compiler say, "okay, how do I convert and int to a pointer". That's going to be either a sign extension or zero extension of the low order 32-bits that it has been told malloc "returns" by omitting the prototype. Since int is signed I think the conversion will be sign extension, which will in this case convert the value to zero. With a return value of 0xABF0000000 you'll get a non-zero pointer that will also cause some fun when you try to dereference it.
A Reusable Software Rule:
In the case of writing an inline function in which used malloc(), in order to make it reusable for C++ code too, please do an explicit type casting (e.g. (char*)); otherwise compiler will complain.
A void pointer in C can be assigned to any pointer without an explicit cast. The compiler will give warning but it can be reusable in C++ by type casting malloc() to corresponding type. With out type casting also it can be use in C, because C is no strict type checking. But C++ is strictly type checking so it is needed to type cast malloc() in C++.
The malloc() function could often require a conversion cast before.
For the returned type from malloc it is a pointer to void and not a particular type, like may be a char* array, or a string.
And sometimes the compiler could not know, how to convert this type.
int size = 10;
char* pWord = (char*)malloc(size);
The allocation functions are available for all C packages.
So, these are general functions, that must work for more C types.
And the C++ libraries are extensions of the older C libraries.
Therefore the malloc function returns a generic void* pointer.
Cannot allocate an object of a type with another of different type.
Unless the objects are not classes derived from a common root class.
And not always this is possible, there are different exceptions.
Therefore a conversion cast might be necessary in this case.
Maybe the modern compilers know how to convert different types.
So this could not be a great issue, when is doing this conversion.
But a correct cast can be used, if a type conversion is possible.
As an example: it cannot be cast "apples" to "strawberries". But these both, so called "classes", can be converted to "fruits".
There are custom structure types, which cannot be cast directly.
In this case, any member variable has to be assigned separately.
Or a custom object would have to set its members independently.
Either if it is about a custom object class, or whatever else...
Also a cast to a void pointer must be used when using a free call.
This is because the argument of the free function is a void pointer.
free((void*)pWord);
Casts are not bad, they just don't work for all the variable types.
A conversion cast is also an operator function, that must be defined.
If this operator is not defined for a certain type, it may not work.
But not all the errors are because of this conversion cast operator.
With kind regards, Adrian Brinas