简体   繁体   中英

Necessary to cast NULL to struct pointer type for assignment/comparison in C?

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

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) {

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).

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.

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.

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.

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:

    \npMyObject = NULL; \n

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

    \nwarning: '=' conversion from 'void*' to 'struct foo*' \nwarning: '=' conversion from 'int' to 'struct foo*' \n

    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 :

    \nhMyWindow = CreateWindow(NULL, NULL, WM_OVERLAPPED, 0, 0, 100, 100, NULL, NULL, NULL, NULL); \nif (hMyWindow == NULL) \n    ... \n

    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:

    \nhMyWindow = CreateWindow((LPCTSTR) NULL, (LPCTSTR) NULL, WM_OVERLAPPED, 0, 0, 100, 100, (HWND) NULL, (HMENU) NULL, (HINSTANCE) NULL, (LPVOID) NULL); \nif (hMyWindow == (HWND) NULL) \n    ... \n

    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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM