'\0' not accepted as an empty "const char *": is this a compiler problem or not?

Stephen J. Butler stephen.butler at gmail.com
Mon Jun 20 23:44:18 PDT 2016


'\0' is a single character, not a string. Note the use of signal quote
marks, THIS IS IMPORTANT. It is an 8bit value equivalent to the byte 0x00,
or an integer 0x00000000. You could replace '\0' with 0x00 everywhere in
your code and they would be exactly the same.

"" is a string containing one byte, '\0'. It's equivalent to a byte array
like { 0x00 }. This array is allocate somewhere in memory, not a literal
value in your program like the previous example.

When you say "const char *" that's a C-ism for saying you want an array of
bytes. An array in C is passed by the address of the first element. This is
why clang (correctly) throws a warning.

In your first case, clang sees you have a literal 0x00 when a pointer value
is expected. But it says "Hey, I can take that literal 0x00 and cast it to
a pointer value!" It throws a warning because this isn't usually a good
thing to do, but in this case it is equivalent to NULL so it kind of works.
For example, if you had used a literal 'A', then clang would pass in the
pointer value 0x41, which would try to access whatever memory is at address
0x00000041, which is almost certainly crash.

In your second case, clang sees you have an array of one byte (it doesn't
care about the arrays contents), and passes the address of the first
element of the array. This array is allocated in the global data section of
your program. Let's pretend the address of that first element is 0xDEADBEEF.

Can you see the difference? In the first case clang has to cast character
(or integer) to a char*, which is usually dangerous. In the second case it
is given the proper type (a memory address) that the function argument says
it wants.

It's would really worry me that the upstream developers of this package
don't understand the difference.

On Tue, Jun 21, 2016 at 1:21 AM, Mojca Miklavec <mojca at macports.org> wrote:

> Hi,
>
> When I tried porting some software (originally written for Windows and
> now asking for C++14) to MacPorts I was stuck with an external piece
> of a code written in C, compiled with C++ (I don't fully understand
> why it is compiled with C++, but I cannot change that).
>
> This is a minimal example that fails:
>
>     void test(const char *a) {}
>     int main()
>     {
>         test('\0'); // pass an empty string
>         return 0;
>     }
>
>
> A relatively recent clang++ compiler just throws a warning (using
> libstdc++):
>
> > clang++-mp-3.7 test-dev.c
> clang: warning: treating 'c' input as 'c++' when in C++ mode, this
> behavior is deprecated
> test-dev.c:5:10: warning: expression which evaluates to zero treated
> as a null pointer constant of type 'const char *'
> [-Wnon-literal-null-conversion]
>     test('\0');
>          ^~~~
> 1 warning generated.
>
>
> But the same compiler in C++11 or C++14 mode throws an error:
>
> > clang++-mp-3.7 -stdlib=libc++ -std=c++14 test-dev.c
> clang: warning: treating 'c' input as 'c++' when in C++ mode, this
> behavior is deprecated
> test-dev.c:5:5: error: no matching function for call to 'test'
>     test('\0');
>     ^~~~
> test-dev.c:1:6: note: candidate function not viable: no known
> conversion from 'char' to 'const char *' for 1st argument
> void test(const char *a) {}
>      ^
> 1 error generated.
>
>
> GCC doesn't seem to care though:
>
> > g++-mp-4.9 -std=c++14 test-dev.c
> > # no warnings or errors
>
>
> I didn't test on Windows. I installed clang 3.5 on Linux (the latest
> version shipped by Debian-based Mint) and the results were the same as
> on Mac:
>
> > clang++-3.5 -std=c++11 tes-dev.c
> clang: warning: treating 'c' input as 'c++' when in C++ mode, this
> behavior is deprecated
> test-dev.c:4:5: error: no matching function for call to 'test'
>     test('\0');
>     ^~~~
> test-dev.c:1:6: note: candidate function not viable: no known
> conversion from 'char' to 'const char *' for 1st argument
> void test(const char *a) {}
>      ^
> 1 error generated.
>
> > clang++-3.5 test-dev.c
> clang: warning: treating 'c' input as 'c++' when in C++ mode, this
> behavior is deprecated
> test-dev.c:4:10: warning: expression which evaluates to zero treated
> as a null pointer constant of type 'const char *'
> [-Wnon-literal-null-conversion]
>     test('\0');
>          ^~~~
> 1 warning generated.
>
> I came up with a workaround, defining
>
>    const char *empty = "";
>    test(empty);
>
>
> The upstream developers replied:
>
> first:
> > If I'm understanding correctly, it also seems like a bug in the C++
> > compiler to think that a character constant is not const,
>
> second:
> > If I understand the patch well, the C code supplies a character \0
> > when an empty string is expected. In K&R C it is the same but strictly
> > checking in C++ they are different things.
>
>
> So I was wondering which compiler was right: g++ or clang++?
>
> Mojca
> _______________________________________________
> macports-dev mailing list
> macports-dev at lists.macosforge.org
> https://lists.macosforge.org/mailman/listinfo/macports-dev
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.macosforge.org/pipermail/macports-dev/attachments/20160621/406928be/attachment-0001.html>


More information about the macports-dev mailing list