2

My teacher at school keeps converting NULL to (struct foo *) before assigning it to a pointer to a structure foo. For example:

struct foo {
   // smthg else
   struct foo *ptr;
};

struct foo *bar;
bar = (struct foo*)malloc(sizeof(struct foo));
bar->ptr = (struct foo *) NULL;

What boggles me is that the only time he tests to see whether that value is NULL (checking if the linked list has ended) he does the following

if (aux->ptr != (struct foo *) NULL) {
   ...
}

I asked him why, if it was to "grow" the size of NULL to prevent errors or something. But no, he told me (quite reluctant, I think) it was in order to prevent some possible error by the compiler (wtf?). Is that really necessary?

EDIT:

The language he's teaching is C. He probably doesn't know that casting malloc in C is unnecessary. I wish to know if he's just careful or incompetent. :P

FRD
  • 2,254
  • 3
  • 19
  • 24
  • Perhaps related to (why not to): http://stackoverflow.com/questions/605845/do-i-cast-the-result-of-malloc and http://stackoverflow.com/questions/3477741/why-does-c-require-a-cast-for-malloc-but-c-doesnt –  May 09 '12 at 05:28
  • 3
    In C++, you have to cast the return from `malloc`, but you do *not* have to cast `0`/`NULL` to become a void pointer. Conversion of `0`/`NULL` to a void pointer has been around so long it's hard to imagine a compiler that got it wrong. One that did would be so broken that adding the cast would be about as likely to make things worse as better. – Jerry Coffin May 09 '12 at 05:29
  • I can assure you that he's teaching C. – FRD May 09 '12 at 05:29
  • 4
    If I were you, I'd be doubting your teacher's competence if he says you "need" to cast `NULL`. – Mysticial May 09 '12 at 05:29
  • Most likely a C++ thing, this may not be necessary in C though. But listen to your teacher, there must be some compiler dependent errors. – Shivam May 09 '12 at 05:31
  • @FRD: He *thinks* he's teaching C. But he seems to be teaching the hideous language that is the intersection of C and C++. – R.. GitHub STOP HELPING ICE May 09 '12 at 15:48

6 Answers6

7

To answer your question: No, it is not necessary to cast NULL to a specific pointer type. The compiler makes a special case for NULL and allows it to be assigned to any pointer type without pointer type conversion warnings.

Similarly, it is not necessary to cast when comparing against NULL, either:

if (aux->ptr != NULL) {
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
4

The correct form of

struct foo *bar = (struct foo*)malloc(sizeof(struct foo));

in C is always

struct foo *bar = malloc(sizeof *bar);

Your professor is wrong and probably picked up bad habits from trying to use malloc in C++ (which is generally frowned upon, for good reasons).

R.. GitHub STOP HELPING ICE
  • 208,859
  • 35
  • 376
  • 711
2

There used to be buggy compilers which had #define NULL 0 and the 0 was not a null pointer constant as required by the (C89) C Standard. These days, you'd be very unlikely to come across such a compiler.

It used to matter in contexts such as execl("cmd", "arg0", "arg1", NULL); because that NULL needs to be a null pointer constant, but...these days, NULL is a null pointer constant and therefore the cast really isn't necessary even there. For an assignment operation, you can just write 0 instead of a cast NULL. In the execl() example, you can't just write 0; that's an int and not necessarily a null pointer constant.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • It's also conceivable that there are bad C headers that use `#define NULL ((void*) 0)`, in which case an explicit cast would be necessary. – jamesdlin May 09 '12 at 07:03
  • Why would an explicit cast be necessary? All object pointers are the same size as each other and there is implicit conversion between `void *` and an 'any other object pointer'; all function pointers are the same size as each other; POSIX (but not C) requires that function pointers and object pointers are the same size. – Jonathan Leffler May 09 '12 at 14:22
  • 1
    You're wrong about `execl`. Since it's a variadic function, the cast `(char *)0` or `(char *)NULL` is necessary. Whether `NULL` is defined as `0` or `((void *)0)` or something else, it will not have the required type for `execl`, and since `execl` is a variadic function, no automatic conversion to the right type can happen. – R.. GitHub STOP HELPING ICE May 09 '12 at 15:47
  • @JonathanLeffler: Oops, I didn't realize that this question was restricted to C. I meant for a case where such a C header is used in C++ code. – jamesdlin May 09 '12 at 17:09
1

In C, the result of malloc does not need to be cast to the variable type. In C++, it must be, or else you'll get a compile-time error (cannot implicitly convert void * to your_class *).

If your teacher is trying to teach you sound coding principles, the cast is needed. If your teacher is trying to teach you C in prep for C++, learning to use the cast is needed. And there's nothing "wtf" about the teacher saying "in order to prevent some possible error by the compiler" - you should probably take his advice more often. Assuming your professor to be ignorant is probably not the way to go.

Mahmoud Al-Qudsi
  • 28,357
  • 12
  • 85
  • 125
  • 4
    I disagree -- casting the result of `malloc` is always a lousy idea. In C you shouldn't do it because it can cover up the bug of forgetting to `#include `. In C++, you shouldn't be using `malloc` at all. – Jerry Coffin May 09 '12 at 05:30
  • +1 never assume your professor is ignorant, just lazy and preoccupied with there next book there publishing. (sorry I have that problem) – UNECS May 09 '12 at 05:32
  • @JerryCoffin Forgetting to include `stdlib.h` is always brought up, but that's something that you're bound to discover one way or another. Notice that I provided reasons as to why the professor would be teaching the code in this manner - I believe they're sound reasons. And I didn't mean that malloc should be used in C++, just that casting from `void *` to some other pointer requires an explicit cast (malloc or no malloc). – Mahmoud Al-Qudsi May 09 '12 at 05:34
  • @MahmoudAl-Qudsi: Uses of `void *` in C++ are fairly unusual. It does happen in allocators or templates that automatically cast from `void *` to `T *`. In normal application-level code, it `void *` should be viewed with nearly the same distrust as `goto`. – Jerry Coffin May 09 '12 at 05:38
  • He's not trying to teach C in preparation for C++. There's no C++ on the grade. This is not a college course either. – FRD May 09 '12 at 05:38
  • If you're just here to hear us put your professor down, you're wasting your time. – Mahmoud Al-Qudsi May 09 '12 at 05:54
  • @JerryCoffin: with our without casting the return value of malloc I get the same warning with gcc ("incompatible implicit declaration...") and error with g++ ("‘malloc’ was not declared...") – steffen May 09 '12 at 06:29
1

It is not necessary to cast NULL to a specific pointer type, as NULL is #defined as 0. The only reason I can think of is educational in the sense that it is good to remember the types of objects and pointers as you write your program.

In C++ you would use nullptr for initialisation and compile with g++ -std=c++0x

Finally, it IS necessary to cast the return value of malloc in C++, not in C. In C++ you should use 'new', though.

steffen
  • 8,572
  • 11
  • 52
  • 90
-2

The correct answer to this question is that your teacher is not wrong, and he/she's not ignorant either. He/she is just teaching you good habits. Using an explicit cast is not a must, but there are at least two very good reasons why you should.

  1. Code Portability

    Using an explicit cast ensures your code is portable between ANSI C compilers, pre-ANSI compilers, and most importantly, non ANSI C compliant compilers. Your teacher's code should not generate errors or warnings with any compiler, compliant or non-compliant, past, present or future.

    If compiling on any platform that pre-dates ANSI C or is not ANSI compliant, writing the code:

    pMyObject = NULL;
    

    could, on some systems, generate compiler warnings along the lines of:

    warning: '=' conversion from 'void*' to 'struct foo*'
    warning: '=' conversion from 'int' to 'struct foo*'
    

    The purpose of the compiler warning is to alert you to a potential problem, therefore code that compiles with even a single warning should not be considered production-quality code unless the warning is fixed with an explicit cast.

  2. Code Readability

    Using an explicit cast greatly improves readability. For example, take the following real world example based on the Microsoft Windows SDK:

    hMyWindow = CreateWindow(NULL, NULL, WM_OVERLAPPED, 0, 0, 100, 100, NULL, NULL, NULL, NULL);
    if (hMyWindow == NULL)
        ...
    

    Unless you refer to the Microsoft Windows SDK, it is obvious that you will not understand what parameters are being passed to this function. However, if I write:

    hMyWindow = CreateWindow((LPCTSTR) NULL, (LPCTSTR) NULL, WM_OVERLAPPED, 0, 0, 100, 100, (HWND) NULL, (HMENU) NULL, (HINSTANCE) NULL, (LPVOID) NULL);
    if (hMyWindow == (HWND) NULL)
        ...
    

    then I know, in an instant: 1) the type of variable hWindow, 2) return type for CreateWindow(), 3) type of every function parameter. Virtually everything I need to know to understand this code, and I don't have to scan the current file, or look for another header file, or waste time browsing the internet looking for the API documentation. This makes code self documenting, and this is especially important if you are in one of the many non-graphical environments that do not have built-in code browsing support.

In ANSI C99 (ISO/IEC 9899:1999, Section 6.5.16.1), ANSI agreed on the concept of the NULL pointer constant, and that assignment of the NULL pointer constant to a pointer of a typed object was legal.

However the real reason your teacher taught you the above method is because he/she is simply being just like any good teacher and preparing you for the real world, and in the real world the ANSI C standard is not the law. It does not have to be followed, and in most cases it is not followed. Compiler companies ignore or extend any standard if there is financial profit or market share to be gained. Furthermore, there are lots of proprietary computer systems in existence, some by the world's biggest manufacturers, where non-ANSI C compliant compilers are installed and are being used to compile C programs because they have to support non-standard hardware.

This is why using an explicit cast when doing any pointer operation involving NULL is a very good habit to get into. It will ensure that your code is quickly understandable, compiles cleanly, and works as expected across the massive variety of platforms and compiler tools you will encounter in later life.

aps2012
  • 1,602
  • 12
  • 8