Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Warning for a cast from a char literal to a char *

I can't find a warning for the following in Visual Studio. I turned on /Wall but still get nothing:

const char * pointer = '\0';

gcc won't compile it for C++11, C++14, or C++17:

[x86-64 gcc 7.2 #1] error: invalid conversion from 'char' to 'const char*' [-fpermissive]

gcc will compile with the above as a warning if I pass -fpermissive:

[x86-64 gcc 7.2 #1] warning: invalid conversion from 'char' to 'const char*' [-fpermissive]

clang won't compile for C++11, C++14, or C++17:

[x86-64 clang 5.0.0 #1] error: cannot initialize a variable of type 'const char *' with an rvalue of type 'char'

I'm asking because of the below code that ended up in our codebase, apparently with no warnings:

std::ofstream file;
//...
file.write('\0', 20);

Is there a way to turn on a warning for this in Visual Studio?

like image 566
Millie Smith Avatar asked Nov 08 '22 14:11

Millie Smith


1 Answers

Visual Studio 2015 only allows this conversion with const values of '\0'. Examples:

char c = '\0';
const char cconst = '\0';

const char * p1 = c;      //error (not even warning)
const char * p2 = cconst; //ok
const char * p3 = '\0';   //ok
const char * p4 = '\1';   //error (not even warning)

The specific error is:

Error: a value of type "char" cannot be used to initialize an entity of type "const char *"

Apple LLVM 8.1.0 (clang-802.0.41) gives a warning with C++03 but an error with C++11 and later. The behavior was changed sometime between the Feb. 28, 2011 (draft N3242 and May 15, 2013 (draft N3690). I can't find the exact point.

In earlier drafts of C++, such as n1905, the OP code is defined as a valid conversion:

A null pointer constant is an integral constant expression (5.19) rvalue of integer type that evaluates to zero. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of pointer to object or pointer to function type. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4).

Section 3.9.1.2 defines the signed integer types:

There are five signed integer types: “signed char”, “short int”, “int”, “long int”, and “long long int”.

This was changed in later drafts. In draft N3690 from 2013, section 4.10 says:

A null pointer constant is an integer literal (2.14.2) with value zero or a prvalue of type std::nullptr_t. A null pointer constant can be converted to a pointer type; the result is the null pointer value of that type and is distinguishable from every other value of object pointer or function pointer type. Such a conversion is called a null pointer conversion. Two null pointer values of the same type shall compare equal. The conversion of a null pointer constant to a pointer to cv-qualified type is a single conversion, and not the sequence of a pointer conversion followed by a qualification conversion (4.4).

character-literal is a defined as a literal in section 2.14.1, but it does not appear in section 2.14.2. Instead it gets its own section - 2.14.3.

C++17 draft n4659 has the exact same verbiage but in different sections.

I don't see a way to give a warning for this in VS 2015. This would be another reason to run static analysis tools / other compilers to catch extra warnings.

Thanks to @EricPostpischil for the help.

like image 106
Millie Smith Avatar answered Nov 14 '22 21:11

Millie Smith