Chinaunix首页 | 论坛 | 博客
  • 博客访问: 918227
  • 博文数量: 132
  • 博客积分: 9976
  • 博客等级: 中将
  • 技术积分: 1781
  • 用 户 组: 普通用户
  • 注册时间: 2007-08-30 20:40
文章分类

全部博文(132)

文章存档

2013年(1)

2011年(1)

2010年(15)

2009年(77)

2008年(36)

2007年(2)

我的朋友

分类: C/C++

2008-03-12 18:11:44

NULL 和 '\0' 的区别的问题

我感觉很可能是 NULL 和 '\0' 是不等价的, 实践中得出的经验。


来自网络的:

1。============================================

> > NULL, 0, \0 and nul?

This item was added on: 2003/03/13

NULL is a macro defined in several standard headers, 0 is an integer constant, '\0' is a character constant, and nul is the name of the character constant. All of these are *not* interchangeable:

NULL is to be used for pointers only since it may be defined as ((void *)0), this would cause problems with anything but pointers.

0 can be used anywhere, it is the generic symbol for each type's zero value and the compiler will sort things out.

'\0' should be used only in a character context.

nul is not defined in C or C++, it shouldn't be used unless you define it yourself in a suitable manner, like:

#define nul '\0'

Credit: Prelude



2。 ============================================
引自: 《推荐好好看看》

6.7 如果 NULL 和 0 作為空指針常數是等價的, 那我到底該用哪一個呢?

許多程序員認為在所有的指針上下文中都應該使用 NULL, 以表明該值應該被看作指針。 另一些人則認為用一個宏來定義 0, 只不過把事情搞得更複雜, 反而令人困惑。因而 傾向於使用未加修飾的 0。沒有正確的答案。 (參見問題  和 ) C 程序員應該明白, 在指針上下文中  NULL 和 0 是完全等價的, 而未加修飾的 0 也完全可以接受。任何使用 NULL  (跟 0 相對) 的地方都應該看作一種溫和的提示, 是在使用指針; 程序員 (和編譯器都) 不能依靠它來區別指針 0 和整數 0。

在需要其它類型的 0 的時候, 即便它可能工作也不能使用 NULL, 因為這樣做發出了錯誤的格式信息。(而且, ANSI 允許把 NULL 定義為 ((void *)0), 這在非指針的 上下文中完全無效。特別是, 不能在需要 ASCII 空字符 (NUL) 的地方用 NULL。如果有必要, 提供你自己的定義

    #define NUL '\0'


3。 ============================================
源自:

关于NULL,nil,0(其实都知道,只不过我把他整理成册了)(一)


 日期:2006-9-17 3:24:00     [Host01.Com]   访问:     []

用过

C++Delphi的程序员都知道,C++中的NULLDelphi中为nil,意思是空指针

 

C++ (void*)0 Dlephi Pointer(0)

但是,这不是绝对,因为Handle


C++Handle,是一个指针


DelphiHandle,被理解为一个整数了,于是一切差别就从这里开始


先看一个函数吧! CreateWindow

C++的申明为:

HWND CreateWindow(

    LPCTSTR lpClassName, // pointer to registered class name

    LPCTSTR lpWindowName,       // pointer to window name

    DWORD dwStyle, // window style

    int x,      // horizontal position of window

    int y,       // vertical position of window

    int nWidth,       // window width

    int nHeight,       // window height

    HWND hWndParent, // handle to parent or owner window

    HMENU hMenu,   // handle to menu or child-window identifier

    HANDLE hInstance,     // handle to application instance

    LPVOID lpParam        // pointer to window-creation data

);

让我们来看看有几个指针(7个,返回值,前两个参数,后四个参数)

让我们再来看看在Delphi中的申明:

function CreateWindow(

    lpClassName: PChar;    // pointer to registered class name

    lpWindowName: PChar;   // pointer to window name

    dwStyle:Integer;     // window style

    x: Integer;       // horizontal position of window

    y: Integer;       // vertical position of window

    nWidth: Integer;  // window width

    nHeight: Integer;  // window height

    hWndParent: Integer;  // handle to parent or owner window

    hMenu: Integer;  // handle to menu or child-window identifier

    hInstance: Integer;  // handle to application instance

    lpParam: Pointer   // pointer to window-creation data

 ): Integer;

有几个指针呢?(有三个,前两个和最后一个参数)


如果在调用此函数时,夸张一点,将所有指针(以C++)全用NULL代替的话,在Delphi中,函数调用应是这样的:

hWnd:= CreateWindow( ’’,’’, ws_Child, 0,0,100,100,0,0,0,nil); //此函数只是例子


可见如果NULL指的是Handle的话,在Delphi中,它等价与0;其他吗?等价于nil(PChar暂且搁下)(见第二篇)

 

以上是我的一些看法,愿大家指正



4。 ============================================
源自: 《应该是引文2的原文》

Section 1. Null Pointers

The language definition states that for each pointer type, there is a special value -- the "null pointer" -- which is distinguishable from all other pointer values and which is not the address of any object or function.  That is, the address-of operator & will never yield a null pointer, nor will a successful call to malloc (malloc returns a null pointer when it fails, and this is a typical use of null pointers: as a "special" pointer value with some other meaning, usually "not allocated" or "not pointing anywhere yet.")

A null pointer is conceptually different from an uninitialized pointer.  A null pointer is known not to point to any object; an uninitialized pointer might point anywhere.  See also questions , , and .

As mentioned in the definition above, there is a null pointer for each pointer type, and the internal values of null pointers for different types may be different.  Although programmers need not know the internal values, the compiler must always be informed which type of null pointer is required, so it can make the distinction if necessary (see below).

References: Sec. 5.4 pp. 97-8; Sec. 5.4 p. 102; Sec. 5.3 p. 91; Sec. 3.2.2.3 p. 38.

According to the language definition, a constant 0 in a pointer context is converted into a null pointer at compile time.  That is, in an initialization, assignment, or comparison when one side is a variable or expression of pointer type, the compiler can tell that a constant 0 on the other side requests a null pointer, and generate the correctly-typed null pointer value. Therefore, the following fragments are perfectly legal:

	char *p = 0;
if(p != 0)

However, an argument being passed to a function is not necessarily recognizable as a pointer context, and the compiler may not be able to tell that an unadorned 0 "means" a null pointer.  takes a variable-length, null-pointer-terminated list of character pointer arguments.  To generate a null pointer in a function call context, an explicit cast is typically required, to force the 0 to be in a pointer context:

	execl("/bin/sh", "sh", "-c", "ls", (char *)0);

If the (char *) cast were omitted, the compiler would not know to pass a null pointer, and would pass an integer 0 instead. (Note that many Unix manuals get this example wrong.)

When function prototypes are in scope, argument passing becomes an "assignment context," and most casts may safely be omitted, since the prototype tells the compiler that a pointer is required, and of which type, enabling it to correctly convert unadorned 0's.  Function prototypes cannot provide the types for variable arguments in variable-length argument lists, however, so explicit casts are still required for those arguments.  It is safest always to cast null pointer function arguments, to guard against varargs functions or those without prototypes, to allow interim use of non- compilers, and to demonstrate that you know what you are doing.  (Incidentally, it's also a simpler rule to remember.)

Summary:

Unadorned 0 okay:

  • initialization
  • assignment
  • comparison
  • function call, prototype in scope, fixed argument
Explicit cast required:
  • function call, no prototype in scope
  • variable argument in varargs function call

References: Sec. A7.7 p. 190, Sec. A7.14 p. 192; Sec. A7.10 p. 207, Sec. A7.17 p. 209; Sec. 4.6.3 p. 72; Sec. 3.2.2.3 .

NULL and how is it #defined?

As a matter of style, many people prefer not to have unadorned 0's scattered throughout their programs.  For this reason, the preprocessor macro NULL is #defined (by or ), with value 0 (or (void *)0, about which more later).  A programmer who wishes to make explicit the distinction between 0 the integer and 0 the null pointer can then use NULL whenever a null pointer is required.  This is a stylistic convention only; the preprocessor turns NULL back to 0 which is then recognized by the compiler (in pointer contexts) as before.  In particular, a cast may still be necessary before NULL (as before 0) in a function call argument.  (The table under above applies for NULL as well as 0.)

NULL should only be used for pointers; see .

References: Sec. 5.4 pp. 97-8; Sec. 5.4 p. 102; Sec. 13.1 p. 283; Sec. 4.1.5 p. 99, Sec. 3.2.2.3 p. 38,

NULL be #defined on a machine which uses a nonzero bit pattern as the internal representation of a null pointer?

Programmers should never need to know the internal representation(s) of null pointers, because they are normally taken care of by the compiler.  If a machine uses a nonzero bit pattern for null pointers, it is the compiler's responsibility to generate it when the programmer requests, by writing "0" or "NULL," a null pointer.  Therefore, #defining NULL as 0 on a machine for which internal null pointers are nonzero is as valid as on any other, because the compiler must (and can) still generate the machine's correct null pointers in response to unadorned 0's seen in pointer contexts.

NULL were defined as follows:

	#define NULL ((char *)0)

wouldn't that make function calls which pass an uncast NULL work?

Not in general.  The problem is that there are machines which use different internal representations for pointers to different types of data.  The suggested #definition would make uncast NULL arguments to functions expecting pointers to characters to work correctly, but pointer arguments to other types would still be problematical, and legal constructions such as

	FILE *fp = NULL;

could fail.

Nevertheless, C allows the alternate

	#define NULL ((void *)0)

definition for NULL Besides helping incorrect programs to work (but only on machines with homogeneous pointers, thus questionably valid assistance) this definition may catch programs which use NULL incorrectly (e.g. when the ASCII  NUL character was really intended; see ).

References:

	#define Nullptr(type) (type *)0

to help me build null pointers of the correct type.

This trick, though popular in some circles, does not buy much. It is not needed in assignments and comparisons; see .  It does not even save keystrokes.  Its use suggests to the reader that the author is shaky on the subject of null pointers, and requires the reader to check the #definition of the macro, its invocations, and all other pointer usages much more carefully.  See also .

"if(p)" to test for non- null pointers valid?  What if the internal representation for null pointers is nonzero?

When C requires the boolean value of an expression (in the if, while, for, and do statements, and with the &&, ||, !, and ?: operators), a false value is produced when the expression compares equal to zero, and a true value otherwise.  That is, whenever one writes

	if(expr)

where "expr" is any expression at all, the compiler essentially acts as if it had been written as

	if(expr != 0)

Substituting the trivial pointer expression "p" for "expr," we have

	if(p)	is equivalent to     if(p != 0)

and this is a comparison context, so the compiler can tell that the (implicit) 0 is a null pointer, and use the correct value. There is no trickery involved here; compilers do work this way, and generate identical code for both statements.  The internal representation of a pointer does not matter.

The boolean negation operator, !, can be described as follows:

	!expr   is essentially equivalent to    expr?0:1

It is left as an exercise for the reader to show that

	if(!p)	is equivalent to	if(p == 0)

"Abbreviations" such as if(p), though perfectly legal, are considered by some to be bad style.

See also .

References: Sec. A7.4.7 p. 204; Sec. 5.3 p. 91; Secs. 3.3.3.3, 3.3.9, 3.3.13, 3.3.14, 3.3.15, 3.6.4.1, and 3.6.5 .

"NULL" and "0" are equivalent, which should I use?

Many programmers believe that "NULL" should be used in all pointer contexts, as a reminder that the value is to be thought of as a pointer.  Others feel that the confusion surrounding "NULL" and "0" is only compounded by hiding "0" behind a #definition, and prefer to use unadorned "0" instead.  There is no one right answer.  C programmers must understand that "NULL" and "0" are interchangeable and that an uncast "0" is perfectly acceptable in initialization, assignment, and comparison contexts.  Any usage of "NULL" (as opposed to "0") should be considered a gentle reminder that a pointer is involved; programmers should not depend on it (either for their own understanding or the compiler's) for distinguishing pointer 0's from integer 0's.

NULL should not be used when another kind of 0 is required, even though it might work, because doing so sends the wrong stylistic message.  ( allows the #definition of NULL to be (void *)0, which will not work in non-pointer contexts.)  In particular, do not use NULL when the ASCII null character (NUL) is desired.  Provide your own definition

	#define NUL '\0'

if you must.

References: Sec. 5.4 p. 102.

NULL (rather than 0) in case the value of NULL changes, perhaps on a machine with nonzero null pointers?

No.  Although symbolic constants are often used in place of numbers because the numbers might change, this is not the reason that NULL is used in place of 0.  Once again, the language guarantees that source-code 0's (in pointer contexts) generate null pointers.  NULL is used only as a stylistic convention.

  NULL is guaranteed to be 0, but the null pointer is not?

When the term "null" or "NULL" is casually used, one of several things may be meant:

  1. The conceptual null pointer, the abstract language concept defined in .  It is implemented with...
  2. The internal (or run-time) representation of a null pointer, which may or may not be all-bits-0 and which may be different for different pointer types.  The actual values should be of concern only to compiler writers.  Authors of C programs never see them, since they use...
  3. The source code syntax for null pointers, which is the single character "0".  It is often hidden behind...
  4. The NULL macro, which is #defined to be "0" or "(void *)0" Finally, as red herrings, we have...
  5. The ASCII null character (NUL), which does have all bits zero, but has no necessary relation to the null pointer except in name; and...
  6. The "null string," which is another name for an empty string ("").  The term "null string" can be confusing in C (and should perhaps be avoided), because it involves a null ('\0') character, but not a null pointer, which brings us full circle...
This article always uses the phrase "null pointer" (in lower case) for sense 1, the character "0" for sense 3, and the capitalized word "NULL" for sense 4.

  Why do these questions come up so often?

C programmers traditionally like to know more than they need to about the underlying machine implementation.  The fact that null pointers are represented both in source code, and internally to most machines, as zero invites unwarranted assumptions.  The use of a preprocessor macro (NULL) suggests that the value might change later, or on some weird machine.  The construct "if(p == 0)" is easily misread as calling for conversion of p to an integral type, rather than 0 to a pointer type, before the comparison.  Finally, the distinction between the several uses of the term "null" (listed above) is often overlooked.

One good way to wade out of the confusion is to imagine that C had a keyword (perhaps "nil", like Pascal) with which null pointers were requested.  The compiler could either turn "nil" into the correct type of null pointer, when it could determine the type from the source code, or complain when it could not. Now, in fact, in C the keyword for a null pointer is not "nil" but "0", which works almost as well, except that an uncast "0" in a non-pointer context generates an integer zero instead of an error message, and if that uncast 0 was supposed to be a null pointer, the code may not work.

  I just can't understand all this null pointer stuff.

Follow these two simple rules:

  1. When you want to refer to a null pointer in source code, use "0" or "NULL".
  2. If the usage of "0" or "NULL" is an argument in a function call, cast it to the pointer type expected by the function being called.

The rest of the discussion has to do with other people's misunderstandings, or with the internal representation of null pointers (which you shouldn't need to know), or with C refinements.  Understand questions , , and , and consider and , and you'll do fine.

If for no other reason, doing so would be ill-advised because it would unnecessarily constrain implementations which would otherwise naturally represent null pointers by special, nonzero bit patterns, particularly when those values would trigger automatic hardware traps for invalid accesses.

Besides, what would this requirement really accomplish?  Proper understanding of null pointers does not require knowledge of the internal representation, whether zero or nonzero.  Assuming that null pointers are internally zero does not make any code easier to write (except for a certain ill-advised usage of calloc; see ).  Known-zero internal pointers would not obviate casts in function calls, because the size of the pointer might still be different from that of an int.  (If "nil" were used to request null pointers rather than "0," as mentioned in , the urge to assume an internal zero representation would not even arise.)

The Prime 50 series used segment 07777, offset 0 for the null pointer, at least for PL/I.  Later models used segment 0, offset 0 for null pointers in C, necessitating new instructions such as TCNP (Test C Null Pointer), evidently as a sop to all the extant poorly-written C code which made incorrect assumptions.  Older, word-addressed Prime machines were also notorious for requiring larger byte pointers (char *'s) than word pointers (int *'s).

The Eclipse MV series from Data General has three architecturally supported pointer formats (word, byte, and bit pointers), two of which are used by C compilers: byte pointers for char * and void *, and word pointers for everything else.

Some Honeywell-Bull mainframes use the bit pattern 06000 for (internal) null pointers.

The CDC Cyber 180 Series has 48-bit pointers consisting of a ring, segment, and offset.  Most users (in ring 11) have null pointers of 0xB00000000000.

The Symbolics Lisp Machine, a tagged architecture, does not even have conventional numeric pointers; it uses the pair (basically a nonexistent handle) as a C null pointer.

Depending on the "memory model" in use, 80*86 processors (PC's) may use 16 bit data pointers and 32 bit function pointers, or vice versa.

The old HP 3000 series computers use a different addressing scheme for byte addresses than for word addresses; void and char pointers therefore have a different representation than an int (structure, etc.) pointer to the same address would have.

This message, which occurs only under MS-DOS (see, therefore, ) means that you've written, via an uninitialized and/or null pointer, to location zero.

A debugger will usually let you set a data breakpoint on location 0.  Alternately, you could write a bit of code to copy 20 or so bytes from location 0 into another buffer, and periodically check that it hasn't changed.



============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


============================================


阅读(1311) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~