Do I cast the result of malloc?
Solution 1
TL;DR
int *sieve = (int *) malloc(sizeof(int) * length);
has two problems. The cast and that you're using the type instead of variable as argument for sizeof. Instead, do like this:
int *sieve = malloc(sizeof *sieve * length);
Long version
No; you don't cast the result, since:
- It is unnecessary, as
void *
is automatically and safely promoted to any other pointer type in this case. - It adds clutter to the code, casts are not very easy to read (especially if the pointer type is long).
- It makes you repeat yourself, which is generally bad.
- It can hide an error if you forgot to include
<stdlib.h>
. This can cause crashes (or, worse, not cause a crash until way later in some totally different part of the code). Consider what happens if pointers and integers are differently sized; then you're hiding a warning by casting and might lose bits of your returned address. Note: as of C99 implicit functions are gone from C, and this point is no longer relevant since there's no automatic assumption that undeclared functions returnint
.
As a clarification, note that I said "you don't cast", not "you don't need to cast". In my opinion, it's a failure to include the cast, even if you got it right. There are simply no benefits to doing it, but a bunch of potential risks, and including the cast indicates that you don't know about the risks.
Also note, as commentators point out, that the above talks about straight C, not C++. I very firmly believe in C and C++ as separate languages.
To add further, your code needlessly repeats the type information (int
) which can cause errors. It's better to de-reference the pointer being used to store the return value, to "lock" the two together:
int *sieve = malloc(length * sizeof *sieve);
This also moves the length
to the front for increased visibility, and drops the redundant parentheses with sizeof
; they are only needed when the argument is a type name. Many people seem to not know (or ignore) this, which makes their code more verbose. Remember: sizeof
is not a function! :)
While moving length
to the front may increase visibility in some rare cases, one should also pay attention that in the general case, it should be better to write the expression as:
int *sieve = malloc(sizeof *sieve * length);
Since keeping the sizeof
first, in this case, ensures multiplication is done with at least size_t
math.
Compare: malloc(sizeof *sieve * length * width)
vs. malloc(length * width * sizeof *sieve)
the second may overflow the length * width
when width
and length
are smaller types than size_t
.
Solution 2
In C, you don't need to cast the return value of malloc
. The pointer to void returned by malloc
is automagically converted to the correct type. However, if you want your code to compile with a C++ compiler, a cast is needed. A preferred alternative among the community is to use the following:
int *sieve = malloc(sizeof *sieve * length);
which additionally frees you from having to worry about changing the right-hand side of the expression if ever you change the type of sieve
.
Casts are bad, as people have pointed out. Especially pointer casts.
Solution 3
You do cast, because:
- It makes your code more portable between C and C++, and as SO experience shows, a great many programmers claim they are writing in C when they are really writing in C++ (or C plus local compiler extensions).
- Failing to do so can hide an error: note all the SO examples of confusing when to write
type *
versustype **
. - The idea that it keeps you from noticing you failed to
#include
an appropriate header file misses the forest for the trees. It's the same as saying "don't worry about the fact you failed to ask the compiler to complain about not seeing prototypes -- that pesky stdlib.h is the REAL important thing to remember!" - It forces an extra cognitive cross-check. It puts the (alleged) desired type right next to the arithmetic you're doing for the raw size of that variable. I bet you could do an SO study that shows that
malloc()
bugs are caught much faster when there's a cast. As with assertions, annotations that reveal intent decrease bugs. - Repeating yourself in a way that the machine can check is often a great idea. In fact, that's what an assertion is, and this use of cast is an assertion. Assertions are still the most general technique we have for getting code correct, since Turing came up with the idea so many years ago.
Solution 4
As others stated, it is not needed for C, but necessary for C++. If you think you are going to compile your C code with a C++ compiler, for whatever reasons, you can use a macro instead, like:
#ifdef __cplusplus
# define NEW(type, count) ((type *)calloc(count, sizeof(type)))
#else
# define NEW(type, count) (calloc(count, sizeof(type)))
#endif
That way you can still write it in a very compact way:
int *sieve = NEW(int, 1);
and it will compile for C and C++.
Solution 5
From the Wikipedia:
Advantages to casting
Including the cast may allow a C program or function to compile as C++.
The cast allows for pre-1989 versions of malloc that originally returned a char *.
Casting can help the developer identify inconsistencies in type sizing should the destination pointer type change, particularly if the pointer is declared far from the malloc() call (although modern compilers and static analyzers can warn on such behaviour without requiring the cast).
Disadvantages to casting
Under the ANSI C standard, the cast is redundant.
Adding the cast may mask failure to include the header stdlib.h, in which the prototype for malloc is found. In the absence of a prototype for malloc, the standard requires that the C compiler assume malloc returns an int. If there is no cast, a warning is issued when this integer is assigned to the pointer; however, with the cast, this warning is not produced, hiding a bug. On certain architectures and data models (such as LP64 on 64-bit systems, where long and pointers are 64-bit and int is 32-bit), this error can actually result in undefined behaviour, as the implicitly declared malloc returns a 32-bit value whereas the actually defined function returns a 64-bit value. Depending on calling conventions and memory layout, this may result in stack smashing. This issue is less likely to go unnoticed in modern compilers, as they uniformly produce warnings that an undeclared function has been used, so a warning will still appear. For example, GCC's default behaviour is to show a warning that reads "incompatible implicit declaration of built-in function" regardless of whether the cast is present or not.
If the type of the pointer is changed at its declaration, one may also, need to change all lines where malloc is called and cast.
Although malloc without casting is preferred method and most experienced programmers choose it, you should use whichever you like having aware of the issues.
i.e: If you need to compile C program as C++ (Although it is a separate language) you must cast the result of use malloc
.
Patrick McDonald
.NET Developer, F#, C#, ASP.NET MVC, previously VB.NET, VB6
Updated on July 23, 2022Comments
-
Patrick McDonald almost 2 years
In this question, someone suggested in a comment that I should not cast the result of
malloc
. i.e., I should do this:int *sieve = malloc(sizeof(*sieve) * length);
rather than:
int *sieve = (int *) malloc(sizeof(*sieve) * length);
Why would this be the case?
-
Hosam Aly about 15 yearsSince you're using a macro anyway, why don't you use
new
in the definition of C++? -
quinmars about 15 yearsBecause there is no reason to do so. It is mainly for C programs that are compiled with a C++ compiler. If you are going to use 'new', the only thing you get are problems. You need then also a macro for free. And you need a macro to free an array, a differentiation that doesn't exists in C.
-
quinmars about 15 yearsNot to mention if it's not you who frees the memory but maybe a C library you are using, etc. Many possible problems without any gain.
-
Hosam Aly about 15 yearsHmmm... I didn't think of that. Is it an error to use
free()
to free memory allocated withnew
? -
Graeme Perrow almost 13 years@Hosam: Yes, it definitely is. If you use
new
you must usedelete
and if you usemalloc()
you must youfree()
. Never mix them. -
EFraim about 12 years@Jens: OK, maybe the more proper wording is "implicit conversion". Like use of integral variable in floating point expression.
-
hyde about 11 years@ulidtko In case you did not know, it's possible to write code which compiles both as C and as C++. In fact most header files are like this, and they often contain code (macros and inline functions). Having a
.c
/.cpp
file to compile as both is not useful very often, but one case is adding C++throw
support when compiled with C++ compiler (butreturn -1;
when compiled with C compiler, or whatever). -
paulm about 11 yearsIf someone had malloc calls inline in a header I wouldn't be impressed, #ifdef __cplusplus and extern "C" {} are for this job, not adding in extra casts.
-
chux - Reinstate Monica almost 11 yearsFunctions, variables, keywords and macros that only differ in case, though allowed, provide small differentiation. Maybe
CNEW(t, n)
-
Jonathan Baldwin almost 11 yearsAlso nets you compatibility with compilers which compile C as C++ by default. (<cough>MSVC</cough>)
-
quinmars over 10 years@chux, well,
new
is not a keyword in C and in a real C++ program I wouldn't use this macro at all, so no confusion. -
Elias Van Ootegem over 10 yearsWell, point 1 is irrelevant, since C != C++, the other points are also trivial, if you use the variable in your
malloc
call:char **foo = malloc(3*sizeof(*foo));
if quite full-proof: 3 pointers to char pointers. then loop, and dofoo[i] = calloc(101, sizeof(*(foo[i])));
. Allocate array of 101 chars, neatly initialized to zeroes. No cast needed. change the declaration tounsigned char
or any other type, for that matter, and you're still good -
Norwæ about 10 yearsCasting will not hide an error - in fact it introduces the possibility for further errors (casting an int to pointer, most obviously)
-
mah about 10 yearsIf one is going to take this approach, calling the macro
NEW
is probably a bad idea since the resource is never returned usingdelete
(orDELETE
) so you're mixing your vocabulary. Instead, naming itMALLOC
, or ratherCALLOC
in this case, would make more sense. -
Lundin almost 10 yearsExcept as already mentioned, the cast might hide bugs and make the code harder to analyse for the compiler or static analyser.
-
chux - Reinstate Monica over 9 years"Essentially casting will not change anything in how it works". Casting to the matching type should not change anything, but should the var's type change and the cast no longer match, could problems come up? IWOs, the cast and var type should be kept in sync - twice the maintenance work.
-
DrBeco over 9 yearsWhen I tought I got it, there it comes! Fantastic answer. Its the first time here in StackOverflow that I +1 two opposite answers! +1 No, you dont cast, and +1 Yes, you do cast! LOL. You guys are terrific. And for me and my students, I made my mind: I do cast. The kind of errors students make are more easily spotted when casting.
-
Dave Branton over 9 yearsI'd be pretty unhappy seeing a #define used in this way. I guess if there's really no other option, it might be ok. But one day you're going to wish you hadn't done it. At least give the damn thing a better name than NEW.
-
quinmars over 9 years@DaveBranton, in what way do you see the use of
#define
critically? The macro does not alter any variable, the variable is only used once, it's a simple expression and not a sequence of statements. Plus, it cannot be done with a inline function. So I wonder what makes you worry. -
Ray Toal over 9 yearsInteresting that @Leushenko was the only commenter here to state the very important point that the casting is not DRY. IMHO that is a showstopper and why I do not cast in C. I suck it up in C++ because I have to. That said, "repeating yourself" does have its use: in unit tests. But certainly not in production code. Repeating oneself is just asking for trouble. I'm glad we can all agree to disagree but I can't see myself ever being swayed by the casters' arguments. ;-)
-
Niccolo M. over 9 years
-
Jean-Baptiste Yunès over 9 yearsMaybe donotcasters could read this document: securecoding.cert.org/confluence/display/seccode/…. I'm convinced that do not cast is more dangerous than casting and that casting the result of malloc is not "repeating yourself".
-
Grzegorz Szpetkowski about 9 years@Jean-BaptisteYunès: It's worth looking into comments below of this document. The rationale of
p = malloc(sizeof(gadget))
has little sense, as more idiomatic form would be justp = malloc(sizeof *p)
. They didn't mention, that cast may be dangerous, producing nasty bugs, when<stdlib.h>
header is not present (and C89 compilers are not obligated for any diagnostic in this case), asmalloc
is assumed to return anint
. -
chqrlie about 9 yearsActually it is much safer to add the cast in C if you use this macro. It will allow the compiler to catch this mistake:
long array = NEW_INT(int, n);
-
Luis Colorado about 9 yearsWhy to
#define
a newNEW
if there is an oldnew
operator in C++ ??? malloc(3) and free(3) are severely discouraged use functions from C in C++ (they are supported only for the claim of portability of C into C++). C++ encourages the use ofnew
anddelete
operators instead. -
Michael Anderson about 9 years@MAKZ I'd argue that
malloc(length * sizeof *sieve)
makes it look likesizeof
is a variable - so I thinkmalloc(length * sizeof(*sieve))
is more readable. -
Mohit Jain almost 9 yearsSo, do you also cast the argument of
free()
tovoid *
? -
Toby Speight almost 9 yearsUse a C compiler for C code. Use a C++ compiler for C++ code. No ifs, no buts. Rewriting your C code in C++ is another thing entirely, and may - or may not be - worth the time and the risks.
-
Toby Speight over 8 years"It is not mandatory -- though you must do it" - I think there's a contradiction there!
-
Toby Speight over 8 yearsIt's not a normal use case to compile a single source as both C and C++ (as opposed, say, to using a header file containing declarations to link C and C++ code together). Using
malloc
and friends in C++ is a good warning sign that it deserves special attention (or re-writing in C). -
Toby Speight over 8 years
void*
can be cast to the desired type, but there is no need to do so as it will be automatically converted. So the cast is not necessary, and in fact undesirable for the reasons mentioned in the high-scoring answers. -
Toby Speight over 8 yearsAnd
malloc(length * (sizeof *sieve))
more readable still. IMHO. -
PC Luddite over 8 years@MohitJain That argument makes no sense. In Java, would you cast the argument of a method that takes
Object
? -
August Karlstrom over 8 yearsThe function malloc returns a void pointer in C as well but the rules of the language are different from C++.
-
Bill Woodger over 8 yearsI think you should read this post to someone, and see if they understand what you are trying to say. Then rewrite it, making it clear what you want to say. I really can't understand what your answer is.
-
supercat over 8 years@Leushenko: Repeating yourself in a way that cannot be validated by machine nor by local inspection is bad. Repeating yourself in ways that can be validated by such means is less bad. Given
struct Zebra *p; ... p=malloc(sizeof struct Zebra);
, the malloc can't avoid duplciating information about p's type, but neither the compiler nor local code inspection would detect any problem if one type changed but the other didn't. Change the code top=(struct Zebra*)malloc(sizeof struct Zebra);
and the compiler will squawk if the cast type doesn't matchp
, and local inspection will reveal... -
supercat over 8 years...if the cast type doesn't match the
sizeof
type. Someone examining the version of code with the typecast can know that (if the code compiles cleanly)p
is eithervoid*
orstruct Zebra*
without having to look at the actual declaration ofp
. To my mind that's a win. -
milevyo over 8 yearsis NEW a keyword in c++?. i guess not, and if i am right, the macro by @quinmars is quite a good solution. and there will be no troubles in using it.
-
Mad Physicist over 8 years@EFraim That would actually result in a cast, and an implicit one at that.
-
autistic over 8 yearsI'd like to add to @TobySpeight advice: If you need to use C code in a C++ project, you can usually compile the C code as C (e.g.
gcc -c c_code.c
), the C++ code as C++ (e.g.g++ -c cpp_code.cpp
), and then link them together (e.g.gcc c_code.o cpp_code.o
or vice-versa depending upon the project dependencies). Now there should be no reason to deprive yourself of any nice features of either language... -
autistic over 8 years@user877329 It's a more sensible alternative to painstakingly adding casts to code that reduce the code's legibility, only for the sake of being "C++ compatible".
-
chux - Reinstate Monica over 8 years@Michael Anderson
()
issue aside, note that your suggested style switched the order., Consider when element count is computed likelength*width
, keeping thesizeof
first in this case insures multiplication is done with at leastsize_t
math. Comparemalloc(sizeof( *ptr) * length * width)
vs.malloc(length * width * sizeof (*ptr))
- the 2nd may overflow thelength*width
whenwidth,length
are smaller types thatsize_t
. -
Michael Anderson over 8 years@chux it's not obvious, but the answer has been edited so that my comment is less pertinent - the original suggestion was
malloc(sizeof *sieve * length)
-
Admin over 8 years@LuisColorado This solution is for interop-style code between C and C++. It's not about doing things in a C++-idiomatic way, it's about making C code compile and port easily to a C++ compiler.
-
David C. about 8 yearsC is not C++. Pretending that they are will ultimately lead to confusion and sadness. If you're using C++, then a C-style cast is also bad (unless you're using a very old C++ compiler). And
static_cast>()
(orreinterpret_cast<>()
)is not compatible with any dialect of C. -
Albert van der Horst about 8 years"Repeating yourself in a way that the machine can check". No! If you leave out a cast (in general) you will get a warning if you do something unreasonable, or reasonable and not portable. If you use a cast, you say to the compiler: "Shut up! I've looked into it, and I know better.". Novices should not be taught the habit of putting up casts. malloc() is the one example where adding the cast does comparatively little harm.
-
Albert van der Horst about 8 yearsShutting up compiler warnings is a bad idea.
-
Dan Bechard about 8 years@AlbertvanderHorst Not if you're doing so by solving the exact problem the warning is there to warn you of.
-
Spikatrix almost 8 yearsWhat does "Casting can help the developer identify inconsistencies in type sizing should the destination pointer type change, particularly if the pointer is declared far from the
malloc()
call" mean? Could you give an example? -
Phil1970 almost 8 yearsAs other pointed out, I would usually recommend to not mix C and C++ code. However, if you have good reason to do it, then macros might be useful.
-
Kaz almost 8 years@Phil1970 It's all written in one cohesive dialect, which happens to be portable to C and C++ compilers, and takes advantage of some capabilities of C++. It must be all compiled as C++, or else all compiled as C.
-
Kaz almost 8 yearsI.e. what I was trying to say in the previous comment is that there is no mixing of C and C++. The intent is that the code is all compiled as C or all compiled as C++.
-
Cubic over 7 years@TobySpeight And I'd argue that
calloc(length, sizeof(*sieve))
is more readable than any of the alternatives I've seen proposed on this question. -
Peter Cordes over 7 years@CoolGuy: See an earlier comment on another answer. But note that the
p = malloc(sizeof(*p) * count)
idiom picks up changes in the type automatically, so you don't have to get warnings and go change anything. So this isn't a real advantage vs. the best alternative for not-casting. -
Peter Cordes over 7 yearsOther advantages to C over C++: C99 variable-length arrays for very efficient allocation/deallocation of scratch space. You can't accidentally write non-constant initializers when you didn't mean to (e.g. if you thought you were being clever by putting
static const __m128 ones = _mm_set1_ps(1.0f);
at the global scope so multiple functions could share a constant, the fact that constructors aren't a thing in C stops you from generating worse code. (This is really finding a silver lining to a C limitation...)) -
Peter Cordes over 7 yearsProbably the main advantage in this context is that C lets you write
p = malloc(sizeof(*p));
, which doesn't need changing in the first place ifp
changes to a different type name. The proposed "advantage" of casting is that you get a compile error ifp
is the wrong type, but it's even better if it Just Works. -
Don Hatch over 7 yearsGreat answer, thank you for it. Implicit conversions cause so many problems, and you do a good job of articulating why. Maybe reword the "stupendously stupid" part though? That would probably increase the chance of reaching people who don't already agree with you, rather than putting them on the defensive and making them unable hear the sensible things you're saying.
-
Don Hatch over 7 years"pointless clutter" is dismissive hyperbole that tends to derail any possibility of convincing anyone who doesn't already agree with you. A cast certainly isn't pointless; Ron Burk's and Kaz's answers make arguments in favor of casting that I very much agree with. Whether those concerns weigh more than the concerns you mention is a reasonable question to ask. To me, your concerns look relatively minor compared to theirs.
-
Albert van der Horst over 7 years@Dan . If by solving the exact problem is meant a rewrite of a subroutine to return modern ANSI C types instead of char *, I agree. I wouldn't call that shutting up the compiler. Do not give in to managers who insists that there are no compiler warnings , instead of using them by each recompilation to find possible problems. Groetjes Albert
-
Tom Lint over 7 years@AlbertvanderHorst Novices should enable the compiler flag that turns implicit conversions into errors.
-
Peter - Reinstate Monica over 7 yearsThis is the proper answer: There are pros and cons, and it boils down to a matter of taste (unless the code must compile as C++ -- then the cast is mandatory).
-
n. m. over 7 yearsPlease consider updating the answer. The cast is no longer dangerous, and repeating oneself is not necessarily a bad thing (redundancy can help catch errors).
-
n. m. over 7 yearsCompilers have changed. An up-to-date compiler will warn you about a missing declaration of malloc.
-
unwind over 7 years@n.m. Ok. I think it's bad to assume that anyone reading here has a particular compiler. Also, since C11 the entire "implicit function" concept is gone, I didn't know that. Still, I don't see the point in adding a pointless cast. Do you also do
int x = (int) 12;
just to make things clear? -
n. m. over 7 yearsI've encountered a case where redundancy of the malloc cast helped to find a bug. This doesn't happen often but still.
-
Braden Best over 7 yearsWhen using sizeof with a specific type, I like to separate sizeof and (type) with a single space (I.e.
sizeof (int)
) just to reinforce that the argument to sizeof is(int)
, notint
-
Braden Best over 7 years@n.m. if explicitly casting a void pointer "helped" solve a bug, you more likely encountered undefined behavior, which would mean the program in question likely has a far worse, undiscovered bug that you haven't run into yet. And one day, on a cold winter evening, you'll come home from work to find your GitHub page flooded with issue reports complaining about demons flying out of the users' noses
-
n. m. over 7 years@BradenBest No, this is not the case, even remotely so. You can look at the program in question here.
-
Amin Negm-Awad over 7 years@unwind Even I agree with you,
(int)12
is not comparable.12
is anint
, the cast does simply nothing. The retval ofmalloc()
isvoid *
, not the pointer type casted to. (If it is notvoid *
. So the analogy to(int)12
would be(void*)malloc(…)
what nobody is discussing.) -
P.P over 7 years"I think it's bad to assume that anyone reading here has a particular compiler. Also, since C11 the entire "implicit function" concept is gone, I didn't know that" - It's gone since C99 (not just C11). Any C99 compiler is required to issue a diagnostic if
#include <stdlib.h>
isn't included.Out of the 4 bullets, the first 3 are subjective (there's sufficient proof that some tend to favor it in this page) and the 4th has been "fixed" in C language about 10 years before this answer. While I am not advocating in favor of the cast, it's really a case of making a mountain out of a mole here. -
Ryan Haining about 7 years@unwind comparing with
double d = (double)12;
orunsigned int u = (unsigned int)12;
might make more sense. -
Nguai al almost 7 years"the second may overflow the length * width when width and length are smaller types that size_t." - I don't get this. I thought the variables get promoted to larger type. How is the overflow possible?
-
Gewure almost 7 yearshow comes the compiler is throwing warnings unless i cast the result of malloc?
-
unwind almost 7 years@Nguaial No, promotion has nothing to do with the type of the left-hand side of an assignment. This is a common misconception.
double a = 1 / 2;
is0
since it's an integer division. -
unwind almost 7 years@Gewure Obviously quite hard to answer without your code, but probably because you're failing to
#include <stdlib.h>
formalloc()
's prototype, thus making the compiler assume it returnsint
, which you can't assign to a pointer without a cast. The cast is not enough, in that case. -
AnT stands with Russia almost 7 yearsLots of fallacies in this answer. Basically, the only valid argument is the first one: cross-compilable C/C++ code. But it is only applicable to cross-compilable C/C++ code, not a reason to use the cast everywhere. The remaing arguments are fallacies based on the failure to undestand a simple fact: avoiding the cast is not a purpose in itself, but a part of wider idiomatic practice - writing type-independent/type-agnostic code.
-
AnT stands with Russia almost 7 yearsTha above reasoning tries to solve problems present in
T *p = malloc(N * sizeof(T))
. But you shouldn't do it this way in the first place. The proper idiomatic type-agnostic way to allocate memory calls forT *p = malloc(N * sizeof *p)
, i.e. the type names are not mentioned in size expression at all. This version is completely free of any issues the above answer tries to "solve". In other words, explicit cast on the result of memory allocation function is a classc "solution looking for a problem". A problem you yourself created. Don't create the problem, and you won't need the solution. -
Michaël Roy almost 7 yearsNot reviewing ALL allocations in the code when changing a data type size/switching to a different data type is asking for troubles. you can use casting to your an advantage to quiclky find all malloc calls for a certain type.
-
Michaël Roy almost 7 yearsPoint 3 is moot, since If the type of the pointer is changed at its declaration, one should check every instance of malloc, realloc and free inolving that type. Casting will force you to do just that.
-
tilz0R almost 7 yearsLet's say we have C++ project and C library file where header has
extern "C"...
setup. When compiler compiles .c file, will it work if there is no casting ofmalloc
, because we are in C++ project? -
unwind almost 7 years@tilz0R Yes, of course. The
extern "C"
is for the C++ compiler, it just tells it not to name-mangle when looking for the C function. The C function is built by a C compiler and is written in C. -
tilz0R almost 7 yearsSo then I don't know why we always fight over you cannot write C and C++ code for the same project. I'm using
extern "C"
approach in every my C library so then it is allowed to not castmalloc
and will still compile. Case closed for me then. I'm not casting it anymore then if this is really hidden error if you cast result. In general to me, your 4th point why not cast has no sense, or at least I don't get it. If non NULL is returned, memory is allocated, you can cast it how you want. -
unwind almost 7 years@tilz0R Pre-C11, functions without prototype were assumed to return
int
. Butint
is often smaller thanvoid *
(32 vs 64 bits), so doingfoo *x = (foo *) malloc(sizeof *x);
might have hidden a warning caused by making the (undeclared, assumedint
) return value frommalloc()
be treated as a pointer, when it in fact is not large enough and thus won't work. -
chux - Reinstate Monica almost 7 years"A void pointer can be converted to/from any other pointer type without an explicit cast" is not supported by 6.3.2.3. Perhaps you are thinking of "pointer to any object type"? "void pointer" and "pointer to a function" are not so readily convertible.
-
chux - Reinstate Monica almost 7 yearsI can see why Profs prefer casting. Casting may be useful from an educational standpoint where it conveys to the instructor information and the student code does not need to be maintained - its throw-away code. Yet from a coding, peer-review and maintenance perspective,
p = malloc(sizeof *p * n);
is so simple and better. -
chux - Reinstate Monica almost 7 years"a void pointer can be assigned to any object pointer" Function pointers are another issue, albeit not a
malloc()
one. -
Admin over 6 years@unwind "Pre-C11, functions without prototype were assumed to return int" <- this was already gone in C99.
-
autistic over 6 years@unwind, actually, I think that point which you say is no longer relevant is still relevant because if you try to compile code without specifying
--std=c11
(as many do), you'll get but a mere warning... In fact, even when specifying--std=c11
I get "warning: implicit declaration of function ‘malloc’", when I've not included the standard library header for it. This isn't an uncommon implementation, either; gcc version 5.4.0 20160609... -
autistic over 6 years@unwind There's room for misinterpretation there; some users might think this means "this point is no longer relevant, since it just emits a warning and (erroneously) we can ignore the warning".
-
savram over 6 years"Compare: malloc(sizeof *sieve * length * width) vs. malloc(length * width * sizeof *sieve) the second may overflow the length * width when width and length are smaller types than size_t" I don't understand what overflow can happen here.
-
Daniel H over 6 years@savram If
length
andwidth
areint
s, whereint
has fewer bits thansize_t
, thenlength*width
might be bigger than the largestint
. This is less likely to be an issue if you usesize_t
math, which you can do by putting thesizeof
part first (since the compiler “reads” multiplications from left to right) -
Daniel H over 6 years@Cubic Sure, but if you don’t need the memory zeroed it can be slower on some systems.
-
savram over 6 years@DanielH Thank you, I understand about the int now. But why changing the order solves anything? What if the multiplication of sizeof * length exceeds the largest sizeof?
-
Daniel H over 6 years@savram The
malloc
function takes asize_t
as input. If the whole multiplication exceeds that, then you just can't do the allocation you want. This is unlikely in a bug-free program, because on most 64-bit systems that would be asking for 18 exabytes of memory, more than I think has actually been manufactured ever. On the other hand, the maximumint
on such systems is often 2^31-1, or just over two gigabytes; a lot of programs would want to allocate that much. -
chux - Reinstate Monica over 6 yearsAssigning a
void*
to/from a function pointer may lose information so "a void pointer can be assigned to any pointer," is a problem in those cases. Assigning avoid*
, frommalloc()
to any object pointer is not an issue though. -
autistic about 6 years@DanielH I'd suggest that the bigger problem there is... why was
int
chosen as the type forlength
andwidth
? We should take care in choosing types for our variables, and unless it absolutely makes sense for a length and/or width to be negative, all signed options should be discarded from the choices. After all, you wouldn't want a two-dimensional array where each dimension can have negative indices, right? That's just begging for undefined behaviour. Wouldn't you rather suggest thatlength
andwidth
be refactored assize_t
, to avoid further complications? -
Daniel H about 6 years@Sebivor It depends on the context. Sometimes there are reasons for using
signed
types anyway, and more oftenlength
might be unsigned but smaller thansize_t
for some reason. I agree that, all else being equal, it's better iflength
is asize_t
. I was also answering savram's question about how an overflow could happen withlength * width * sizeof *sieve
, as mentioned in the question; just saying to always makelength
andwidth
be of typesize_t
would not be an answer. -
Lundin about 6 yearsIndeed the reference was incomplete. The relevant part for the "implicitness" is the rule of simple assignment 6.5.16.1. "one operand is a pointer to an object type, and the other is a pointer to a qualified or unqualified version of void". I've added this reference to the answer for completeness.
-
Luis Masuelli about 6 yearsWhy do most of you say casting is bad because if you cast an pointer as an integer you may lose bits depending on the platform if the whole point here is regarding casting
void*
to an arbitrary but neededT*
? -
DimeCadmium almost 6 yearsRegarding sizeof() vs sizeof: yes, it's not a function, but it behaves somewhat like a function (or more accurately a macro I suppose). And also () makes it clear to anyone reading EXACTLY what size you're taking. Personally I feel strongly that the ability to leave off the paren's is a bug, not a feature. @Kevin: this is why you use
sizeof(*x)
, as mentioned in the answer. -
HostileFork says dont trust SE almost 6 yearsI very firmly believe in C and C++ as separate languages. => You shouldn't be firm about things that fly in the face of both history and present practice. C++ didn't inherit C's syntax because of its intrinsic beauty; it was so that C codebases can incrementally adopt C++ features. Plus, there's a lot of value in being able to compile a C codebase with a C++ compiler whether that's how you ultimately ship your binary or not, see the C++ core guidelines. One can write a lot of neat type_traits-based static checks for C.
-
Kemin Zhou over 5 yearsLook the example, do not use a case: en.cppreference.com/w/c/memory/malloc
-
Jonathan Leffler over 5 years@Jean-BaptisteYunès: The SEI reference for MEM02-C: Immediately cast the result of a memory allocation function call into a pointer to the allocated type is at a new location (link valid today; who knows about tomorrow).
-
David 天宇 Wong over 5 yearsThis is ugly, and not initialized. You need to use
calloc
andsizeof()
-
Ryan over 5 years@HostileFork That may have been true back when C++ was just a plain preprocessor on top of C, with a solid philosophy guiding the language. But in the past couple of decades, syntactic creep has left it nearly unrecognizable as a dialect of C. A lot of compliant C code refuses to compile with a C++ compiler (try creating a struct named 'template' with a field named 'class'). Meanwhile the ISO C++ committee has neglected to keep up with modern developments to the ISO C standards, leaving the languages on two separate tracks: one promising portability, and the other boasting flexibility.
-
alx over 5 years@HostileFork @Ryan You don't even have to use C++ keywords to get C/C++ incompatibility: I recently had a problem when I first used C++ because the library I used (OpenCV) was being deprecated in C (WTF!), and the only stable option was to use C++. When I tried to use my C library which includes functions like this one
void foo(int n, int arr[n])
, I realized C++ doesn't allow that, which I think is really stupid (tell me otherwise), and then I decided to do separate headers for C (.h) and for C++ (.hpp) (both referring to C code), even if that means repeating most of the code in the headers. -
Michael Beer over 4 years@Jean-BaptisteYunes: In your mentioned recommendation: MEM02-C-EX1: "Do not immediately cast the results of malloc() for code that will be compiled using a C90-conforming compiler because it is possible for the cast to hide a more critical defect (see DCL31-C. Declare identifiers before using them for a code example that uses malloc() without first declaring it). "
-
mtraceur over 4 years-1 Where/how are you getting "keeping the sizeof first, in this case, ensures multiplication is done with at least
size_t
math"? Pretty sure the standard arithmetic conversions are order-independent. I'll switch to +1 if you remove that claim or clarify that you mean something more nuanced or convince me I'm mistaken. -
mtraceur over 4 yearsI think maybe this idea grew out of the fact that order does make a difference in expressions with more than one operation? For example, the order does make a difference in
sizeof foo * bar * qux
vsbar * qux * sizeof foo
, because the standard arithmetic conversions are local to each operator's arguments instead of being done across the entire expression. That's actually a very good point to warn people about, but we should do it with wording that accurately explains that, whereas the current wording suggests that order matters even in justsize foo * bar
vsbar * sizeof foo
. -
mtraceur over 4 yearsGreat, comprehensive answer otherwise, to be clear. Would've been an immediate +1 were it not for the above.
-
mathematrucker over 4 yearsWhen I changed
arr = (Array *)malloc(sizeof(Array))
toarr = malloc(sizeof arr)
my program started crashing, and changing it back fixed the problem, so I've decided to stick with the unpopular casting approach. -
Ferrarezi over 4 yearsbut only if you need to dereference it "on the fly", if you create a variable instead it will be converted safely and automatically into the variable's effective type, without casting (in C).
-
RobertS supports Monica Cellio over 4 years@quinmars One thing to note: When compiling with a C compiler, the provided code uses
calloc()
instead ofmalloc()
, just because of the sake of symmetry between the two definitions.malloc()
isn´tcalloc()
.calloc()
may be slower when it initialises the zeros. On the other hand, it could be also more benefitial. But this is another question, see stackoverflow.com/q/1538420/12139179. But since the question is asked formalloc()
I would rather do it like that:#else #define NEW(type, count) (malloc(sizeof(type) * count))
-
user7860670 over 4 yearsI would like to mention that writing in C may be necessary when targeting platforms lacking proper C++ compilers. Exceptions and templates are features that typically help c++ to generate smaller and / or more efficient code while runtime polymorphism in C++ is mostly equivalent to C.
-
nneonneo over 4 years@mathematrucker uh, you changed the size of your allocation from
sizeof(Array)
tosizeof arr
. The latter is the size of a pointer, not the size of your structure, so of course your program started crashing. -
mathematrucker about 4 years@nneonneo thanks I don't remember exactly what my code was now (I changed it for the comment) but I see what you're saying maybe I just needed to dereference.
-
Matt about 4 yearsI'm used to writing
int* sieve
rather thanint *sieve
. When writing thesizeof *sieve
part, would it be the same if I wrotesizeof* sieve
? Am I even using a healthy convention? -
unwind about 4 years@Matt Yes, it would be the same. Whether or not your convention is healthy or not is probably cause for enough religious wars. I personally don't use it, since it makes things like
int* a, b
very confusing, basically you're trying to shape the syntax into something it is not which I find confusing. Of course you could also have a convention never to declare more than variable per declaration (and have another war around that) but I find that wasteful. :) Sorry for not being definitive. -
Lundin almost 4 yearsThis is pretty much the same thing as said in this old answer though: stackoverflow.com/a/22538350/584518.
-
Ctx almost 4 years@Lundin You must have pasted the wrong link, this answer is completely unrelated to this one afaics
-
RobertS supports Monica Cellio almost 4 years@Lundin While I usually like content of yours very much, I need to fully disagree with you at this point here. There is a big difference between your answer and mine. Your answer clearly suggest to omit the cast in a very opinion-based way. In fact, your and unwind's answers were one of the main reasons, why I did this answer here. - You speak about "You don't cast the result of malloc, because doing so adds pointless clutter to your code." and "The most common reason why people cast the result of malloc is because they are unsure about how the C language works." which are not correct.
-
RobertS supports Monica Cellio almost 4 years"Clutter" is a construct of one's own opinion. I completely disagree with the usage of that term in any way related to any question here on SO. That being said, I point back to Don Hatch's comment to your answer.
-
RobertS supports Monica Cellio almost 4 yearsThe latter quote suggest that only users who aren't familiar with C or don't know what they are actually doing use casting. That is totally in conflict with my answer.
-
Lundin almost 4 years@RobertSsupportsMonicaCellio What would you call the cast in this expression:
int x, y; x = (int)y;
then? A matter of subjective coding style? -
RobertS supports Monica Cellio almost 4 years@Lundin This example has already been object by unwind in the comments to his question. My answer to that is equal to Amin Negm-Awad's comment.
-
RobertS supports Monica Cellio almost 4 years@Lundin I admit that the second quote is technically correct, but in the context it suggests a different meaning. IMHO It needs to be said explicitly that there is nothing wrong about casting as is, even it's something unsure beginners do often. As it now is, it gives the impression to me that it would actually be a mistake beginners do. - The difference is subtle but important to avoid your statements being ambiguous.
-
underscore_d almost 4 yearsIt's not the fact that
void*
can point to anything that enables this; it's the fact that avoid*
can be implicitly converted to any other pointer type. To clarify the distinction, in C++ avoid*
can still point to anything, but implicit conversion was removed, so one must cast. -
Konrad Rudolph almost 4 yearsThis is a bad answer because it relies on the implicit claim that all arguments in this debate are of equal value, whereas this is obviously not the case. The arguments in favour of the cast — with one niche exception (adherence to external code style requirements) — are simply bad arguments, for various reasons (from subjective to factually wrong). It’s fallacious to conclude that, just because sides have nominal “arguments”, the decision is therefore a toss-up, or opinion-based. In the same vein you’d both-side the non-scientific debates about biological evolution or global warming.
-
RobertS supports Monica Cellio almost 4 years@KonradRudolph I don't see how opinion-based arguments in favor of the omission of the cast would have more value than arguments about that it is being allowed and can be used and I also do not understand why all of the given arguments for casting are "bad" arguments. The classification as "bad" is also subjective and opinion-based and what I wanted to prevent with this answer with just plain facts.
-
tripulse over 3 years
int *sieve = reinterpret_cast<int*>(malloc(sizeof(*sieve) * length))
is the best quality code one can write, it was written by the gods of C++. -
Chris Dodd over 3 yearsWhen you write
int *sieve = malloc(length * sizeof *sieve);
you are "needlessly" repeating the name of the object (sieve
) and violating the DRY principle. So why is this better than repeating theint
? -
Stargateur over 3 years@ChrisDodd variable name are mean to be reuse not type of one variable.
-
SO_fix_the_vote_sorting_bug over 3 years
sizeof(*sieve) * length
is more readable, and not only issizeof *sieve * length
just plain silly, it is purely a subjective call to make. Also, you have a Black & White fallacy in your implied argument. Would you writea = b * 2 + c
if you wanta
to equalb * (2 + c)
? Isb *
a function? Of course not. We don't use parentheses only for functions, they have many other uses. -
SO_fix_the_vote_sorting_bug over 3 years+1 for "forest for the trees" comment. FFS, how many programmers would forget to
#include <stdlib.h>
and then not figure it out whenmalloc
isn't being called? It's like warning newbies of the pitfalls of forgetting to define amain
function. "Whatever shall we do?! We cannot recover and it could remain a hidden bug for years!" Where do programmers pick up these absurd memes? -
tstanisl about 3 yearssince C99 one can write
malloc(sizeof(int[length]))
-
Stargateur about 3 years@tstanisl since C11 one can't anymore (And that good)
-
tstanisl about 3 years@Stargateur I do not think it's good. I understand issues with automatic VLAs but what's wrong with VM types?
-
Peter - Reinstate Monica about 3 yearsI agree very much with this answer, except for "C and C++ are in fact two completely different languages with different semantics" which is another favorite argument used to disrespect C/C++ tagged questions with something entirely unrelated, exactly like this "don't cast malloc". C++ has been intentionally designed so that correct C (89) programs are usually correct C++ programs with exactly the same semanics! The languages are emphatically not completely different and typically have exactly the same semantics (with some unfortunate and lamented deviations, e.g. concerning
volatile
). -
chqrlie almost 3 yearsWith your approach, the cast is actually useful in the C version to detect type mismatches such as:
long *sieve; ... ; sieve = NEW(int, 1);
-
SO_fix_the_vote_sorting_bug almost 3 yearsIf one forgets to include stdlib.h, and the program compiles, how does it link without a definition for malloc? If it links and runs anyway, which instructions actually get run on that line for any given CPU? I guess I should check godbolt...
-
William Pursell over 2 yearsIn C++, the code smell is not from the cast, but from the use of malloc. You should not be using malloc at all in C++. Therefore, you shouldn't be casting the result.
-
John Bollinger over 2 yearsThe argument that "keeping the
sizeof
first, in this case, ensures multiplication is done with at leastsize_t
math" is completely bogus. The order of the operands of a*
operator does not affect the result of applying the usual arithmetic conversions to them, and that's ultimately what determines the data type for the operation and result. Personally, I find it easier to read the version with thesizeof
second. -
marcus about 2 yearsOh c'mon how can you forget to include stdlib.h and not have thousands of other warnings in your code? This is a bogus argument. It's not the lack of cast that will save you. There will be lots of undeclared macros and functions to trigger that warning. Unless your code is a single line calling malloc with a very old compiler that still accepts implicit declarations.
-
FrankHB almost 2 yearsThe suggested idea (for the 1st problem) is bad because C's lack of difference of the notion of a call to an allocation function (to get a plain
void*
value) and an allocation of an object (to get a pointer value to an allocated object) as different intentional uses (like this answer), which cause serious confusion in resource management. -
FrankHB almost 2 yearsUnfortunately C has neither function templates nor
new
-expressions like in C++. Despite to interoperation to C++ or function prototyping (and irrelevant to the version of C), this lack of the expressive forms is a real defect of C (at least as a statically typed language), and it is occasionally hidden by coercion tovoid*
, which is an instance of (obvious wrong use of) ad-hoc polymorphism. The ignorance in this point is widespread among C users (like in @unwind 's reply) and probably leads to bad resource management code in productions implemented in C. -
FrankHB almost 2 yearsIt may still worth preventing the confusion in the cost of verbosity of the cast; albeit this is only a workaround to the C language. As of the 2nd problem (
sizeof
), it is both applicable in C and C++, hence inconsistent to the claim of "that the above talks about straight C, not C++" in the answer. -
FrankHB almost 2 yearsNote it is plausible to have the coercion in ancient C because of the some vague notions (e.g. object lifetime) in the object model, but since C99, the wording of effective type makes the case clearer and more closer to C++. OTOH, in C++, the rules on object lifetime are still far stricter due to the "live" invariant being enforced (esp. with non-trivial ctor & dtor calls), so the traditional way in C is simply logically incorrect. C++ has other cost of the clarification (like
std::launder
and relocatable objects), but this is another story which is also not yet addressed in C. -
FrankHB almost 2 yearsAs I've commented to another answer, the reason is to prevent some confusion by abusing the C language rules. Also you cannot resolve the confusion without the complete rules of object creation of C (including how effective type works), so the reasoning is quite incomplete. OTOH, the similar effects in the source code can be achieved in C++ by a class type with member
template<T> operator T*() const {...}
to replacevoid*
here, but C++ still incurs no such confusion due to the stricter rules. The answer is also incomplete in this sense. -
Lundin almost 2 years@FrankHB What do you mean? The effective type isn't affected by the cast. The returned object does not get an effective type until you write to it ("lvalue access").
-
FrankHB almost 2 yearsThere do exist some wrong answers, though not necessarily to the original question. Notably, since the cast in this context is required in C++ (mentioned frequently here), the question also implies the request to answer the reason behind the differences. (And this time it would not be opinion-based.) Sadly I don't see any analysis about this topic. (No answer mentions the normative rules in C++; even very few answers mention distinguish allocation function calls from object allocations.)
-
FrankHB almost 2 years@quinmars There do exist differences in C's abstraction machine semantics but the code cannot reveal the behavioral differences since they can't contribute to observable behavior. However, if extensions allow things like non-trivial destructor calls on array elements, then there are definitely differences in the generated code. I suggest to adapt to the more complete mental model as C++ to avoid switching it back and forth. Any user ever caring about dtors/finalizers (almost always true with C and C++) shouldn't act as a compiler to do micro optimizations like trivial dtor DCE.
-
FrankHB almost 2 yearsWithout the explicitly annotated type in the declarator, the cast is usually more common misleading by easily confusing between the intent to allocate an object (uninterested the initial value) and to allocate merely some (uninitialized) memory.
-
FrankHB almost 2 yearsThere is no effective type in C until C99. This is the C's analog of C++'s dynamic type. In C++ dynamic types imply the well-typed nature of accessible lvalues at runtime, and it is quite close to the type of objects in languages using latent typing: both are relied on the existence of "living" objects. In C++, the nature also derives the strict aliasing rules by default, and only a few exceptional cases (copied from traditional C) should be noted.
-
FrankHB almost 2 yearsOTOH, for compatibility issues, C's effect type has essentially looser constraints; it does not implies the existence of an object; in contrast, sometimes it is used to determine the creation of an object in the allocated storage. In other words, the concept is more "polymophic" than it needed to be: it can either be the type of an object, or the type of some underlying storage of some object. This is annoying because mostly it is not the programmers' intent. The special implicit conversion rule contributes to confusions in a similar way. (It is not exactly though;
void*
is from C89.) -
FrankHB almost 2 yearsCasts can be bad, but an implicit conversions should be even more evil when the only duty is to work around the lack of abstraction by breaking type safety. Here the implicit conversion, or coercion, is a case of ad-hoc polymorphism, because otherwise the values being converted are in different natural domain; while the C++ cast is just "normal" function invocation (and
Object*
->void*
is implicitly allowed because of subtyping). Abuse of polymorphism seems most smelly among these implicit or explicit conversions; and casts, when really needed, are not that bad. -
FrankHB almost 2 years@WilliamPursell It is true that
malloc
is smelly, but the problem still exists by replacingmalloc
to::operator new
. It is not that bad in C++ because::operator new
is more verbose than a plainnew
expression, so it looks like deliberated. (Usingnew
expressions in C++ should be still blamed because they should be replaced by creations of plain objects/smart pointers/opaque pointers... as possible.) -
FrankHB almost 2 yearsUpdate: I strongly recommend to include WG14 N2577 for everyone who really want to "know how a particular language mechanism works", which highlights the subtle problems and reflects some current consensus on a detailed semantics resolving the "ontological" meaning of some debatable operations under the hood; even though it is not just for this specific topic.