In clang's documentation, I find a strange option:
-fno-signed-char, --signed-char
I know -fno-signed-char
is equivalent to -funsigned-char
, I just wonder:
1. What does it mean by following --signed-char
?
2. Is --signed-char
equivalent to -fsigned-char
?
The documentation says:
-fsigned-char, -fno-signed-char, --signed-char
char is signed
This somewhat cryptic notation means that -fsigned-char
and
--signed-char
both cause char
to be a signed type, and
-fno-signed-char
causes char
to be an unsigned type.
(Part of the reason the documentation is so cryptic is that it is automatically generated from the internal implementation shown below. That's not an excuse, just an explanation.)
Later, the documentation says:
-funsigned-char, -fno-unsigned-char, --unsigned-char
without any further description. The intent is for the user to infer
the meaning from the option names and from the behavior of the similarly
named options above. Specifically, -funsigned-char
and
--unsigned-char
cause char
to be unsigned, and -fno-unsigned-char
causes char
to be signed.
Test program test.c
:
// test.c
// Is `char` signed?
#include <stdio.h> // printf
int main(void)
{
char c = (char)128;
printf("c is %d, so char is %s\n",
(int)c,
(c > 0? "unsigned" : "signed"));
return 0;
}
// EOF
Compiling and running with all six options on Linux/x86_64 using Clang-16.0.0:
$ clang -Wall -fsigned-char test.c && ./a.out
c is -128, so char is signed
$ clang -Wall -fno-signed-char test.c && ./a.out
c is 128, so char is unsigned
$ clang -Wall --signed-char test.c && ./a.out
c is -128, so char is signed
$ clang -Wall -funsigned-char test.c && ./a.out
c is 128, so char is unsigned
$ clang -Wall -fno-unsigned-char test.c && ./a.out
c is -128, so char is signed
$ clang -Wall --unsigned-char test.c && ./a.out
c is 128, so char is unsigned
The clang
driver program options are defined in
clang/include/clang/Driver/Options.td
.
As one example, the --signed-char
option is defined on
line 5669
of version 18.1.8 as an alias for -fsigned-char
:
def _signed_char : Flag<["--"], "signed-char">, Alias<fsigned_char>;
In Clang, the driver options --signed-char
,
--unsigned-char
, -fsigned-char
, and -funsigned-char
were all added
together on 2009-06-05 in
commit 327f0b55936a6.
The driver program interprets these options and maps them to the
-fno-signed-char
option of clang -cc1
(the compiler front-end proper)
starting at
line 3959 of clang/lib/Driver/ToolChains/Clang.cpp
:
// -fsigned-char is default.
if (const Arg *A = Args.getLastArg(options::OPT_fsigned_char,
options::OPT_fno_signed_char,
options::OPT_funsigned_char,
options::OPT_fno_unsigned_char)) {
if (A->getOption().matches(options::OPT_funsigned_char) ||
A->getOption().matches(options::OPT_fno_signed_char)) {
CmdArgs.push_back("-fno-signed-char");
}
} else if (!isSignedCharDefault(T)) {
CmdArgs.push_back("-fno-signed-char");
}
The clang -cc1
option -fno-signed-char
(the only variant it
recognizes) is also defined in Options.td
:
defm signed_char : BoolFOption<"signed-char",
LangOpts<"CharIsSigned">, DefaultTrue,
// ^^^^^^^^^^^^
// effect is to control this language option
NegFlag<SetFalse, [], [ClangOption, CC1Option], "char is unsigned">,
// ^^^^^^^^^
// recognized by clang -cc1
PosFlag<SetTrue, [], [ClangOption], "char is signed">>,
ShouldParseIf<!strconcat("!", open_cl.KeyPath)>;
Since you linked to the documentation of Clang, I assume that's the implementation of interest, so I didn't dig into implementation or history for GCC. But Clang generally follows conventions that GCC established, so if you're interested in the pre-2009 history, that is where the trail goes next.