NULL definition problem on 64 bit system
I'm running on RHEL 5.1 64 bit platfrom using gcc 4.1.2.
I have a utility function:
void str_concat(char *buff, int buffSize, ...);
which concats char * passed in variadic list(...), while last argument should be NULL, to designate end of the arguments. On 64 bit system NULL is 8 bytes.
Now to the problem. My application includes directly/indirectly 2 stddef.h files.
First one is /usr/include/linux/stddef.h which defines NULL as following:
#undef NULL
#if defined(__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif
The second one is /usr/lib/gcc/x86_64-redhat-linux/4.1.2/include/stddef.h
#if defined (_STDDEF_H) || defined (__need_NULL)
#undef NULL /* in case <stdio.h> has defined it. */
#ifdef __GNUG__
#define NULL __null
#else /* G++ */
#ifndef __cplusplus
#define NULL ((void *)0)
#else /* C++ */
#define NULL 0
#endif /* C++ */
#endif /* G++ */
#endif /* NULL not defined and <stddef.h> or need NULL. */
#undef __need_NULL
Of course I need the 2nd one, since it defines NULL as __null (8 bytes), while 1st one defines it as integer 0 (4 bytes).
How do I prevent /usr/include/linux/stddef.h to be inderectly included?
UPD:
Compilation line is pretty straightforward:
g++ -Wall -fmessage-length=0 -g -pthread
Many of you advised to pass (void *)0. This of course will work. The problem that the function is used in many, I mean many places. I'd like to find solution that will give me what C++ standard promises - NULL of 8 byte size.
There's no "NULL definiton problem" in this case. There's a problem with how you are trying to use NULL
in your code.
NULL
cannot be portably passed to variadic functions in C/C++ by itself. You have to explicitly cast it before passing, ie in your case you have to pass (const char*) NULL
as the terminator of the argument list.
Your question is tagged as C++. In any case, regardless of size, in C++ NULL
will always be defined as an integer constant. It is illegal in C++ to define NULL
as a pointer. Since your function expects a pointer ( const char *
), no definition of NULL
will ever work for it in C++ code.
For cleaner code you can define your own constant, like
const char* const STR_TERM = NULL;
and use it in the calls to your function. But you will never be able to meaningfully use just NULL
for that purpose. Whenever a plain NULL
is passed as a variadic argument, it is a blatant portability bug that has to be fixed.
Added: your update claims that "C++ standard promises NULL
of 8 byte size" (on a 64-bit platform I presume). This just doesn't make any sense. C++ standard does not promise anything like that about NULL
.
NULL
is intended to be used as an rvalue. It has no specific size and there's no valid use of NULL
where its actual size might even remotely matter.
Quoting from ISO/IEC 14882:1998, section 18.1 'Types', paragraph 4:
The macro NULL is an implementation defined C++ null pointer constant in this International Standard (4.10).180)
180) Possible definitions include 0 and 0L, but not (void*)0.
One solution - possibly even the best, but certainly very reliable - is to pass an explicit null char pointer to your function calls:
str_concat(buffer, sizeof(buffer), "str1", "str2", ..., (char *)0);
or:
str_concat(buffer, sizeof(buffer), "str1", "str2", ..., (char *)NULL);
This is standard recommended practice for the execl()
function in POSIX systems, for example, and for precisely the same reason - the trailing arguments of a variable-length argument list are subject to usual promotions (char or short to int; float to double), but cannot otherwise be type safe.
It is also why C++ practitioners generally avoid variable-length argument lists; they are not type safe.
Removing the __GNUG__
case, and inverting the ifdef/endif in the second file, BOTH files do:
#undef NULL
#if defined(__cplusplus)
#define NULL 0
#else
#define NULL ((void *)0)
#endif
Which is to say that they define NULL as ((void *)0) for C compilations and 0 for C++.
So the simple answer is "Don't compile as C++".
Your real problem is your desire to use NULL in your variadic arugment list, combined with your compiler's unpredictable argument sizing. What you MIGHT try is writing "(void *)0" instead of NULL to terminate your list, and force the compiler pass an 8-byte pointer instead of a 4-byte int.
链接地址: http://www.djcxy.com/p/49180.html上一篇: DSO的动态符号表有64个以下的条目
下一篇: 64位系统上的NULL定义问题