cdecl(1)

๐Ÿ’– cdecl(1) โ€” General Commands Manual ๐Ÿ’–

ok so bestie, gather round, because today we're learning about cdecl and c++decl, aka the two icons whose whole job is composing and deciphering C & C++ declarations and casts. yes. THE gibberish whisperers. let's get into it ๐Ÿซถ


โœจ SYNOPSIS โœจ

cdecl [options] [command ...]
c++decl [options] [command ...]
explain [options] gibberish

๐ŸŒธ DESCRIPTION ๐ŸŒธ

ok before we even get into the technicals, the manpage opens with two absolute legendary quotes and I need you to feel them:

``I'm still uncertain about the language declaration syntax, where in declarations, syntax is used that mimics the use of the variables being declared. It is one of the things that draws strong criticism, but it has a certain logic to it.'' โ€” Dennis M. Ritchie, Creator of C
``I consider the C declarator syntax an experiment that failed.'' โ€” Bjarne Stroustrup, Creator of C++

the way that even the people who made these languages are side-eyeing the syntax ๐Ÿ˜ญ iconic honestly. anyway.

cdecl is a program for composing and deciphering C (or C++) declarations or casts, aka gibberish. and bestie, that is the technical term, I'm not being shady.

but wait, there's more ๐Ÿ’… โ€” cdecl is also for developing and debugging C preprocessor macros by performing expansion step-by-step. multitasking queen.

and it can be used interactively on a terminal, or it can accept input from one of:

  • the command-line
  • standard input
  • a file

๐ŸŽ€ INVOCATION ๐ŸŽ€

Executable Name

so cdecl is that girl who changes personalities based on what you call her. she may be invoked under a number of different names โ€” either by renaming the executable or by creating either a symbolic or hard link to it. and depending on which name you use:

  • cdecl โ€” runs with the latest supported version of C as the default language.
  • c++decl | cppdecl | cxxdecl โ€” runs with the latest supported version of C++ as the default language.
  • explain โ€” runs with the latest supported version of C as the default language, interpreting the rest of the command-line (if given) as gibberish, performs the conversion to pseudo-English, and then exits.

like, she does the whole thing and dips. respect. ๐Ÿ‘‘

for example (where $ is the shell prompt):

$ explain 'int *const (*p)[4]'
declare p as pointer to array 4 of constant pointer to integer

look at that. gorgeous. no notes. โœจ

โš ๏ธ ok important: for declarations given on the command line, you gotta be careful to either escape or quote shell metacharacters. the shell will absolutely eat your declaration alive if you don't, and then you'll be sad. don't be sad. quote it. ๐Ÿ’–

and the default language can be specified via the cdeclrc file (peep CONFIGURATION FILES for the deets).


First Argument

cdecl will also behave as above if the first non-option argument on the command-line โ€” or the first whitespace separated word thereof โ€” is a cdecl command (see Commands). so she's reading your vibe from word one:

$ cdecl declare p as pointer to array 4 of int
int (*p)[4];

$ c++decl 'reinterpret cast n into pointer to unsigned'
reinterpret_cast<unsigned*>(n)

english in, C out. C in, english out. she's fluent in both directions, we love a bilingual icon ๐ŸŒˆ


Standard Input

if no arguments are given, standard input will be read until end-of-file is encountered or one of the exit, q, or quit commands is read. (three ways to say bye, she's flexible like that ๐Ÿฆ‹)

and here's the cute part: you can use cdecl as you create a C (or C++) program from within an editor. for example, in vi(1), type the declaration in pseudo-English, then filter the line through cdecl:

!!cdecl<CR>

where <CR> is the return key. chef's kiss. ๐ŸคŒ


Interactive Input

if standard input is coming from a terminal, a prompt of either cdecl> or c++decl> will be written to the terminal before each line of input.

and if you're not feeling the prompt energy, you can turn it off with either:

  • the --no-prompt option
  • the -P option
  • or the set noprompt command

and last but not least โ€” cdecl uses the GNU readline(3) library (if available and compiled in) to provide:

  • keyword completion
  • command-line history
  • editing

so you get tab-complete, you get your history, you get to fix your typos. the full experience bestie ๐Ÿ’…โœจ

โœจ OPTIONS โœจ

okay so bestie, real talk: an option argument f means file, n means unsigned integer, and s means string. That's the decoder ring. Now let's go through every single one, no skipping, no cap. ๐Ÿ’–

  • --alt-tokens, -a โ€” Turns on alternative token output. The alternative tokens are: and (&&), and_eq (&=), bitand (&), bitor (|), compl (~), not (!), not_eq (!=), or (||), or_eq (|=), xor (^), and xor_eq (^=). (Supported only in C95 and later.) โœจ
  • --bison-debug, -B โ€” Turns on bison(1) debugging output (if compiled in). The additional output is of grammar productions as they are being reduced by the parser. (This is a debugging aid for developers of cdecl itself.) ๐Ÿ›
  • --color=s, -k s โ€” Sets when to colorize output to s (which is case-insensitive). (See the CDECL_COLORS environment variable about colorization.) The choices for s are:
    • always โ€” Always colorize.
    • auto | isatty | tty โ€” Colorize only when standard output is connected to a TTY (terminal).
    • never โ€” Never colorize.
    • not_file | not_isreg โ€” Colorize only when not writing to a regular file (hence writing to a TTY or pipe). (Specifically, fstat(3) is called on standard output: colorize only if S_IFREG is false.)

This is more useful than isatty since it accommodates the common case of allowing color output to be piped to less(1) and still display in color since less understands SGR (โ€œSelect Graphic Renditionโ€) ASCII terminal escape sequences that produce color.

The default is not_file. ๐ŸŒˆ

  • --commands, -K โ€” Prints a sorted list of all cdecl commands for the current language that may be used as the first argument on a command-line. (See First Argument.) This is intended for consumption by a shell completion function. (See also --options or -O.) ๐Ÿ“œ
  • --config=f, -c f โ€” Specifies the configuration file f to read (see CONFIGURATION FILES). โš™๏ธ
  • --debug[=s], -d[s] โ€” Turns on cdecl debugging output:
    • While parsing a command, prints additional JSON5 output of an abstract syntax tree (AST) as it is being constructed from user input while the parser is reducing grammar productions.
    • While expanding a macro, prints additional JSON5 output of the tokens.
    • If an error or warning message is printed, includes the [file:line] of the code that generated said message.
    • For syntax errors, includes the numeric [id] of the token that caused the error.

(This is a debugging aid for developers of cdecl itself.)

Valid formats for s are:

  • u โ€” Include AST node unique_id values in JSON5 output as an additional debugging aid.

Alternatively, * may be given to mean โ€œallโ€ or - may be given to mean โ€œnone.โ€ ๐Ÿ”

  • --digraphs, -2 โ€” Turns on digraph token output. The digraph tokens are: <: ([) and :> (]). (Supported only in C95 and later.) ๐Ÿ”ฅ
  • --east-const, -e โ€” Turns on โ€œeast constโ€ output where const (plus _Atomic and volatile) are printed to the right (โ€œeastโ€) of the type, e.g.:
 const int i;  // west
 int const j;  // east

(Not supported in K&R C.) ๐ŸŒ…

  • --echo-commands, -E โ€” Echoes commands before their corresponding output, but only when not interactive. (This is primarily useful for associating command output with input in test scripts.) ๐Ÿ“ข
  • --explicit-ecsu=s, -S s โ€” For C++ only, sets the type keywords to s (which is case-insensitive) that should be explicitly included in declarations. Valid formats for s are:
    • e โ€” enum
    • c โ€” class
    • s โ€” struct
    • u โ€” union

Multiple formats may be given, one immediately after the other. Alternatively, * may be given to mean โ€œallโ€ or - may be given to mean โ€œnone.โ€ The default is su. For example, using the default:

 c++decl> declare ps as pointer to struct S
 struct S *ps;
 c++decl> declare pt as pointer to class T
 T *pt;

(See Other Caveats.) For C, enum, struct, and union are always included in declarations. ๐Ÿ—๏ธ

  • --explicit-int=s, -i s โ€” Sets the integer types to s (which is case-insensitive) that should have int explicitly included in declarations. (Normally, int is omitted for short, long, long long, or unsigned declarations where int is implied.) Valid formats for s are:
    • i โ€” All signed integer types.
    • u โ€” All unsigned integer types.
    • [u]{i|s|l[l]} โ€” Possibly unsigned: int, short, long, or long long.

Multiple formats may be given, one immediately after the other, e.g., usl means unsigned short and (signed) long. Parsing is greedy so commas may be used to separate formats. For example, ulll is parsed as unsigned long long and long whereas ul,ll is parsed as unsigned long and long long. Note that since u is both a shorthand and a modifier, iu means all signed and unsigned integer types whereas ui means just unsigned int. Alternatively, * may be given to mean โ€œallโ€ or - may be given to mean โ€œnone.โ€ ๐Ÿ”ข

  • --file=f, -f f โ€” Reads commands from file f. ๐Ÿ“‚
  • --flex-debug, -F โ€” Turns on flex(1) debugging output (if compiled in). The additional output is of lexer rules as they are being tokenized by the lexer. (This is a debugging aid for developers of cdecl itself.) ๐Ÿ›
  • --help, -h โ€” Prints a help message for command-line options and exits. ๐Ÿ†˜
  • --infer-command, -I โ€” Tries to infer a command when an input line doesn't start with any. If an input line starts with a:
    • Macro name, infers expand;
    • C (or C++) declaration, infers explain. ๐Ÿ•ต๏ธ
  • --language=s, -x s โ€” Specifies which version of what language s (which is case-insensitive) to use. (See C AND C++ LANGUAGE VERSIONS for valid languages.) The default is C23 (for cdecl) and C++23 (for c++decl). ๐ŸŒ
  • --lineno=n, -L n โ€” Specifies an integer n to add to all line numbers in error and warning messages. (This is a debugging aid for developers of cdecl itself.)

This is useful when cdecl is called from a shell script with a here document for input. Consider a test-script (showing line numbers) like:

              1 #! /usr/bin/env bash
              2 cdecl --echo-commands --lineno=$LINENO <<END
              3 explain int
              4 END

where $LINENO (the shell environment variable containing the current the line number of the script, in this case, the one cdecl is called on โ€” in this example: 2) is given. When executed, the script will print:

              $ test-script
              cdecl> explain int
                                ^
              3,12: error: declaration expected

where the line number printed is 3 (the starting line number 1 plus 2 from $LINENO) which is the absolute line number within the script as opposed to the here document that makes locating offending lines easier. (See Other Caveats.) ๐Ÿ”Ž

  • --no-buffer-stdout, -b โ€” Sets standard output to unbuffered. (This is a debugging aid for developers of cdecl itself.) ๐Ÿšซ๐Ÿ“ฆ
  • --no-config, -C โ€” Suppresses reading of any configuration file, even one explicitly specified via either --config or -c. ๐Ÿšซ๐Ÿ“„
  • --no-english-types, -T โ€” Prints types in C/C++ (e.g., int), not pseudo-English (e.g., integer) when explaining gibberish. ๐Ÿšซ๐Ÿ‡ฌ๐Ÿ‡ง
  • --no-prompt, -P โ€” Suppresses printing of the prompt. ๐Ÿšซ๐Ÿ’ฌ
  • --no-semicolon, -s โ€” Suppresses printing of a final semicolon for C (and C++) declarations. ๐Ÿšซ;
  • --no-typedefs, -t โ€” Suppresses predefining all but required standard types, e.g., size_t, uint8_t, etc. (See PREDEFINED TYPES.) If given twice, suppresses all standard types. (This is a debugging aid for developers of cdecl itself. Certain results will be incorrect.) โš ๏ธ
  • --no-using, -u โ€” Always declares types with typedef rather than using in C++11 and later. ๐Ÿšซ๐Ÿช„
  • --options, -O โ€” Prints a sorted list of all cdecl options that may be used on a command-line in an easily parsable form. This is intended for consumption by a shell completion function. (See also --commands or -K.) ๐Ÿ“‹
  • --output=f, -o f โ€” Sends all non-error output to file f. ๐Ÿ“ค
  • --permissive-types, -p โ€” Permits keywords in language versions other than the current language as types in pseudo-English. By default, a declaration in C like:
 declare p as pointer to class

would result in an โ€œunsupported type in Cโ€ error even though class could be a valid user-defined type in C. This option permits such declarations. (See Permissive Types.) ๐Ÿ•Š๏ธ

  • --trigraphs, -3 โ€” Turns on trigraph token output. The trigraph tokens are: ??( ([), ??) (]), ??' (^), ??'= (^=), ??! (|), ??!= (|=), ??!??! (||), and ??- (~). (Supported only between C89 and C17 and between C++03 and C++14.) ๐Ÿ”บ
  • --trailing-return, -r โ€” Declares functions and operators using the trailing return type syntax in C++11 and later. ๐Ÿ”™
  • --version, -v โ€” Prints the version number and exits. If given twice, additionally prints the set of configure feature & package options and whether GNU readline(3) (if compiled in) is genuine. ๐Ÿท๏ธ
  • --west-decl=s, -w s โ€” Sets when to print the * for pointer and & and && for references adjacent to the type (โ€œwestโ€) versus adjacent to the name (โ€œeastโ€) to s (which is case-insensitive), e.g.:
 int *p;       // east
 int* q;       // west

Valid formats for s are:

  • b โ€” Block return type.
  • f โ€” Function (and pointer to function) return type.
  • l โ€” User-defined literal return type.
  • o โ€” Operator return type.
  • r โ€” All return types (same as bflo).
  • s โ€” Structured binding.
  • t โ€” Non-return type.

Multiple formats may be given, one immediately after the other. Alternatively, * may be given to mean โ€œallโ€ or - may be given to mean โ€œnone.โ€ The default is r.

However, when more than one name is given in the same declare command for anything other than a structured binding, the *, &, and && are always printed adjacent to the name (โ€œeastโ€):

 cdecl> declare f, g as function returning pointer to char
 char *f(), *g();

๐ŸŒ‡

๐ŸŒˆ C AND C++ LANGUAGE VERSIONS ๐Ÿ’…

Okay bestie, listen โ€” whatever you hand to the --language or -x option, or to the set command, has to be one of these versions down here. And yes, they're case-insensitive, so go off with your lowercase era. ๐ŸŽ€

  • C โ€” grabs the latest supported version of the C language. the freshest drop, no cap.
  • CK&R | CKNR | CKR | K&R | K&RC | KNR | KNRC | KR | KRC | C78 โ€” the pre-ANSI Kernighan & Ritchie version of the C language, exactly as given in the first edition of The C Programming Language. vintage. retro. iconic. ๐Ÿ“ผ
  • C89 | C90 โ€” the C89 (first ANSI C) version of the C language. It adds support for const, enum, long double, signed, unsigned char, unsigned long, unsigned short, void, volatile, and function prototypes. Also adds support for C preprocessor token concatenation via ## and stringification via #. slay.
  • C95 โ€” the C95 version of the C language. Adds support for wchar_t. that's it, that's the whole glow-up. โœจ
  • C99 โ€” the C99 version of the C language. Adds support for _Bool, _Complex, _Imaginary, inline functions, long long, restrict, and static, type-qualified, and variable length array function parameters. Also adds support for C preprocessor variadic macros.
  • C11 โ€” the C11 version of the C language. Adds support for _Alignas, _Atomic, char16_t, char32_t, _Noreturn, and _Thread_local.
  • C17 | C18 โ€” the C17 version of the C language. (Minor revision: no new features. Equivalent to C11.) it's giving filler episode but we still love her. ๐Ÿ™ˆ
  • C23 โ€” the C23 version of the C language. Adds support for alignas, auto (as a deduced type), _BitInt, bool, char8_t, constexpr, [[deprecated]], false, fixed-type enumerations, [[maybe_unused]], [[nodiscard]], nullptr, [[reproducible]], thread_local, true, typeof, typeof_unqual, [[unsequenced]], and the __VA_OPT__ preprocessor macro. main character energy fr fr ๐Ÿ”ฅ
  • C++ โ€” the latest supported version of the C++ language.
  • C++98 โ€” the C++98 version of the C++ language. Adds support for class, constructors, destructors, exception specifications (throw), mutable data members, namespace, new-style casts, overloaded operators, references, pointers to class members, user-defined conversion, and virtual functions. the origin story. ๐Ÿ’–
  • C++03 โ€” the C++03 version of the C++ language. (Minor revision; no new features. Equivalent to C++98.)
  • C++11 โ€” the C++11 version of the C++ language. Adds support for alignas, auto (as a deduced type), [[carries_dependency]], char16_t, char32_t, constexpr, default and delete for member functions, enum class, final, fixed-type enumerations, function trailing return-types, inline namespaces, lambdas, long long, member function ref-qualifiers, noexcept, [[noreturn]], override, rvalue references, thread_local, using (as a typedef synonym), and user-defined literals. THAT is a glow-up. ๐Ÿ’…
  • C++14 โ€” the C++14 version of the C++ language. Adds support for auto and constexpr return types and [[deprecated]].
  • C++17 โ€” the C++17 version of the C++ language. Adds support for inline variables, [[maybe_unused]], nested namespace declarations, [[nodiscard]], and structured bindings.
  • C++20 โ€” the C++20 version of the C++ language. Adds support for auto parameters and parameter packs, char8_t, consteval, constinit, default relational operators, export, nested inline namespaces, [[no_unique_address]], operator<=>, and the __VA_OPT__ preprocessor macro.
  • C++23 โ€” the C++23 version of the C++ language. Adds support for _Atomic, explicit object parameters, static operator(), and zero or more parameters for operator[].
  • C++26 โ€” the C++26 version of the C++ language. Adds support for = delete("reason") and [[indeterminate]].

๐Ÿฆ‹ CDECL LANGUAGE ๐Ÿฆ‹

Commands ๐ŸŽ€

Okay so real quick, before we get into it, here's the lil legend for the syntax, bestie โ€” write it on your hand:

  • [] means zero or one
  • * means zero or more
  • {} means one of
  • | means alternate

Got it? Good. cdecl has the following commands, and I'm about to spill all of them: ๐Ÿ‘‘

cast [s-name] {as|[in]to} english

Composes a C (or C++) cast from pseudo-English.

{const|dynamic|reinterpret|static} cast s-name {as|[in]to} english

Composes a C++ new-style cast from pseudo-English.

declare s-name [, s-name]* as english [width number [bits]]

Composes C (or C++) declarations from pseudo-English with an optional bit-field width (for integral types only).

declare s-name [, s-name]* as english aligned [as|to] { number
[bytes] | english }

Composes C (or C++) declarations from pseudo-English aligned to either a specific number of bytes or the same alignment as english.

declare operator as english

For C++ only, composes an overloaded operator declaration from pseudo-English.

declare store* lambda [[captures] [captures]] [([args])] [returning
english]

For C++ only, composes a lambda declaration from pseudo-English.

declare store* user-defined conversion [operator] [of scope-e s-
name]* returning english

For C++ only, composes a user-defined conversion operator from pseudo-English.

define s-name as english

Defines a type (typedef) from pseudo-English.

#define name [pp-tokens]

Defines an object-like macro that expands into pp-tokens.

#define name([pp-params]) [pp-tokens]

Defines a function-like macro that expands into pp-tokens. Note that the ( must be adjacent to name. no space, bestie, not even one. ๐Ÿ˜ค

enum [class] s-name [: type]

Defines s-name as an enum (or an enum class in C++) type optionally of a fixed underlying type. In C, this is equivalent to:

typedef enum s-name s-name
expand name [([pp-args])] [pp-tokens]

Expands a previously defined macro step by step using the supplied arguments (if given). The additional pp-tokens (if given) are appended and expanded.

explain gibberish [, gibberish]*

Deciphers C (or C++) declarations or a new-style cast (C++ only) into pseudo-English.

explain (gibberish)[s-name]

Deciphers a C (or C++) cast into pseudo-English.

include "path"

Includes the file denoted by path and performs the contained commands. (This is typically used in a configuration file to include another configuration file.) Shell meta characters in path, e.g., ~, are expanded.

Note that include is recognized as a cdecl command only when immediately followed by a string literal. otherwise it's just vibes. ๐Ÿ™ˆ
#include "path"

Same as include, except #include may not end with ; and must be on a line by itself.

{ struct | union | class } s-name

Defines s-name as a struct, union, or class (C++ only) type. In C, this is equivalent to:

typedef { struct | union } s-name s-name
scope-c s-name { [{ scope-c | typedef | using } ;]* }

For C++ only, defines s-name as a scope-c (struct, union, or class) type; or begins a namespace. Also executes zero or more class, struct, typedef, union, or using commands within the scope of s-name thus declaring type(s) within that scope.

set [option [= value] | options | lang]*

In the first form, sets a particular option (see Set Options for valid options); in the second form, prints the current value of all options; in the third form, sets the current language to lang. If no argument is given, it's equivalent to the second form.

show [ s-name | [all] [predefined | user] [glob]] [[as] {english |
typedef | using}]
  • For s-name, shows the definition for a previously defined type (via define, typedef, or using) having that name.
  • For all only, shows all predefined and user-defined types.
  • For predefined, shows only predefined types that are valid in the current language or later.
  • For user, shows only user-defined types that were defined in the current language or later.
  • For either all predefined or all user, shows their respective set of types regardless of the current language.
  • For none of s-name, all, predefined, user, or glob, equivalent to show user.

By default, types are shown as they were defined. If typedef is given, types are shown as typedef declarations. For C++11 or later only, if using is given, types are shown as using declarations.

show { name | [predefined | user] macros }
  • For name, shows the definition for a previously defined macro (via #define) having that name.
  • For predefined, shows only predefined macros that are valid in the current language or later.
  • For user, shows only user-defined macros.
  • For neither predefined nor user, equivalent to show user.
type[def] gibberish [, gibberish]*

Defines types via a C (or C++) typedef declaration.

#undef name

Undefines a previously defined macro. gone. deleted. blocked. ๐Ÿ’€

using name = gibberish

For C++11 or later only, defines a type via a using declaration.

{ help | ? } [ command[s] | command | english | options ]

Prints help that's sensitive to the current programming language (C or C++). By default or when command or commands is given, prints help on cdecl's commands (this section); if command is given, prints help only for that command; if english is given, prints help on pseudo-English (see English below); if options is given, prints help on cdecl's options (see Set Options below).

exit | q[uit]

Quits cdecl. Note that q is recognized as a synonym for quit only when it's the only thing on a line other than whitespace. so don't get cute with it. ๐Ÿซถ


where: ๐ŸŒธ

and here's the lil glossary of the placeholders I just used, so nothing's a mystery:

  • args โ€” A comma-separated list of s-name, english, s-name as english; or one of varargs, variadic, or ... (ellipsis).
  • captures โ€” Optionally either copy by default (or =) or reference by default (or &) followed by a comma-separated list of name or reference to name.
  • name โ€” A valid C (or C++) identifier.
  • operator โ€” A valid C++ operator.
  • s-name โ€” For C, is the same as name; for C++, is either the same as name or is a scoped name that may always be specified using ::, e.g., S::T::x, or in an english context, may alternatively be specified as s-name [of scope-e s-name]*.

๐Ÿ’– and that's the whole command menu, bestie โ€” more coming, don't go anywhere ๐Ÿ’–

  • glob โ€” bestie this one's flexible ๐Ÿ’ซ For C it's just a name; for C++ it's a scoped name that can have :: in it. Either flavor can carry * as a wildcard, like T* (any type name starting with T) or *::T* (any type name starting with T in any top-level scope). And there's a special-case glow-up for C++: glob can start with **:: to match a type name in any scope. iykyk.
  • pp-args โ€” a comma-separated list of valid C (or C++) tokens for macro arguments.
  • pp-params โ€” a comma-separated list of valid C (or C++) identifiers for macro parameters. In C99 and later, the last parameter is allowed to be ....
  • pp-tokens โ€” a set of valid C (or C++) tokens. that's it, that's the whole vibe โœจ
  • scope-c โ€” a C or C++ scope-creating keyword, exactly one of: class, namespace, struct, or union.
  • scope-e โ€” an extended scope-creating keyword: either one of scope-c, or cdecl's own special scope when the specific scope-c is either unknown (because T was never declared before) or just doesn't matter. Like:
c++decl> explain int T::x
declare x of scope T as integer

cdecl knows T is one of scope-c, but it genuinely has no way to know which one, so it uses the generic scope. Same energy the other direction โ€” you can use scope when you don't care which one it is:

c++decl> declare x of scope T as int
int T::x;

Commands are terminated by either a semicolon or a newline. But you can absolutely write commands that span multiple lines โ€” you just have to escape the newlines with \. When a newline is escaped, the next prompt (if prompts are enabled) switches to either cdecl+ or c++decl+, which is the terminal's way of saying "hey, this line is a continuation of the previous one" ๐Ÿซถ

Both C-style /* */ comments (yes, even the ones that span multiple lines) and C++-style // comments inside commands get ignored (but peep Other Caveats). And if you type /* on a line without its closing */ on that same line, the next prompt (if enabled) becomes either cdecl* or c++decl* โ€” meaning everything from here on is continuation of the comment until */ shows up. iconic behavior honestly.

๐ŸŽ€ English ๐ŸŽ€

In what follows, [] means zero or one, * means zero or more, {} means one of, and | means alternate. The only punctuation characters used in pseudo-English are hyphens in hyphenated words, parentheses around and commas between constructor, function, operator, user-defined literal, or block parameters, and brackets around lambda captures.

English is one of:

store* ar-qual* array [number|name|*] of english
store* ar-qual* variable [length] array of english
block [([args])] [returning english]
cv-qual* concept s-name [parameter pack]
store* constructor [([args])]
[virtual] destructor [()]
store* fn-qual* [[non-]member] function [([args])] [returning english]
store* fn-qual* [[non-]member] operator [([args])] [returning english]
cv-qual* pointer to [member of class s-name] english
[rvalue] reference to english
structured binding
store* user-defined literal [([args])] [returning english]
store* modifier* [C-type]
{ enum [class|struct] [of [type] english] | class | namespace | struct | union } s-name

where:

  • ar-qual โ€” one of: non-empty, const, restrict, or volatile.
  • C-type โ€” one of: auto (C23 or C++11 or later), bool, char, char8_t, char16_t, char32_t, wchar_t, int, float, double, parameter pack, or void; or for C99 only: _Accum or _Fract.
  • cv-qual โ€” one of: _Atomic, const, restrict, or volatile.
  • fn-qual โ€” one of: const, final, override, reference, restrict, rvalue reference, or volatile.
  • modifier โ€” one of: short, long, signed, unsigned, _Complex, _Imaginary, or _Sat (C99 only).
  • number โ€” one of a decimal, octal (if starting with 0), hexadecimal (if starting with either 0x or 0X), or binary (if starting with either 0b or 0B) number.
  • store โ€” one of: auto (C17 or earlier, or C++03 or earlier), block, carries-dependency, consteval, constexpr, deprecated, explicit, export, extern, extern "C", final, friend, inline, maybe-unused, mutable, nodiscard, non-throwing, noreturn, override, register, reproducible, static, thread-local, typedef, unsequenced, virtual, or pure virtual.

If returning english is omitted, it's equivalent to returning int in C95 and earlier, or returning void in C99 and later or C++. ๐Ÿ’…

๐ŸŒˆ Synonyms ๐ŸŒˆ

Some synonyms are permitted within pseudo-English. The terms on the left are synonyms for what's on the right:

  • accum โ†’ _Accum
  • atomic โ†’ _Atomic
  • automatic โ†’ auto
  • bit precise integer โ†’ _BitInt
  • bit-precise integer โ†’ _BitInt
  • bool โ†’ _Bool
  • boolean โ†’ _Bool
  • Boolean โ†’ _Bool
  • capture โ†’ capturing
  • captures โ†’ capturing
  • carries dependency โ†’ carries_dependency
  • carries-dependency โ†’ carries_dependency
  • char 8 โ†’ char8_t
  • char 16 โ†’ char16_t
  • char 32 โ†’ char32_t
  • character โ†’ char
  • command โ†’ commands
  • complex โ†’ _Complex
  • constant โ†’ const
  • constant evaluation โ†’ consteval
  • constant-evaluation โ†’ consteval
  • const-eval โ†’ consteval
  • constant expression โ†’ constexpr
  • constant-expression โ†’ constexpr
  • const-expr โ†’ constexpr
  • constant initialization โ†’ constinit
  • constant-initialization โ†’ constinit
  • const-init โ†’ constinit
  • conv โ†’ conversion
  • ctor โ†’ constructor
  • double precision โ†’ double
  • double-precision โ†’ double
  • dtor โ†’ destructor
  • enumeration โ†’ enum
  • eval โ†’ evaluation
  • exported โ†’ export
  • expr โ†’ expression
  • external โ†’ extern
  • floating point โ†’ float
  • floating-point โ†’ float
  • fract โ†’ _Fract
  • func โ†’ function
  • imaginary โ†’ _Imaginary
  • init โ†’ initialization
  • integer โ†’ int
  • len โ†’ length
  • maybe unused โ†’ maybe_unused
  • maybe-unused โ†’ maybe_unused
  • mbr โ†’ member
  • no discard โ†’ nodiscard
  • no-discard โ†’ nodiscard
  • non-discardable โ†’ nodiscard
  • no except โ†’ noexcept
  • no-except โ†’ noexcept
  • no-exception โ†’ noexcept
  • no unique address โ†’ no_unique_address
  • no-unique-address โ†’ no_unique_address
  • non-unique-address โ†’ no_unique_address
  • non-mbr โ†’ non-member
  • noreturn โ†’ _Noreturn
  • no return โ†’ _Noreturn
  • no-return โ†’ _Noreturn
  • non-returning โ†’ _Noreturn
  • non-throwing โ†’ throw()
  • oper โ†’ operator
  • overridden โ†’ override
  • predef โ†’ predefined
  • ptr โ†’ pointer
  • ref โ†’ reference
  • restricted โ†’ restrict
  • ret โ†’ returning
  • sat โ†’ _Sat
  • saturated โ†’ _Sat
  • structure โ†’ struct
  • type โ†’ typedef
  • thread local โ†’ thread_local
  • thread-local โ†’ thread_local
  • thread_local โ†’ _Thread_local
  • user defined โ†’ user-defined
  • user-def โ†’ user-defined
  • var โ†’ variable
  • varargs โ†’ ...
  • variadic โ†’ ...
  • vector โ†’ array
  • wide character โ†’ wchar_t

๐Ÿฆ‹ Gibberish ๐Ÿฆ‹

Gibberish is any supported C (for cdecl) or C++ (for c++decl) declaration of a variable, constant, array, macro, pointer, reference, rvalue reference, function, constructor, destructor, or overloaded operator; or user-defined type, conversion, or literal; or type cast. (Scoot over to EXAMPLES for examples and CAVEATS for the declarations that are not supported, no cap.)

Gibberish also includes support for the following:

  • Apple's "blocks" syntax and the __block storage class. ๐ŸŽ
  • For C99 only, Embedded C's _Accum and _Fract types, and the _Sat modifier.
  • For C99 only, Unified Parallel C's relaxed, shared, and strict qualifiers.
  • GNU C's __auto_type, __complex, __complex__, __const, __inline, __inline__, __restrict, __restrict__, __signed, __signed__, __thread, __typeof__, __volatile, and __volatile__.
  • GNU C's __attribute__ syntax, but heads up โ€” all attributes are ignored.
  • Microsoft C's __declspec syntax, but again, all attributes are ignored.
  • Microsoft C's calling conventions __cdecl, __clrcall, __fastcall, __stdcall (also WINAPI), __thiscall, and __vectorcall. Pseudo-English also allows the same convention names but without the leading __.
  • Microsoft C's __forceinline, but it's treated as a synonym for inline.
  • Microsoft C's _asm, _cdecl, _declspec, _fastcall, _forceinline, _inline, _restrict, _stdcall, and _vectorcall that are synonyms for their respective __ counterparts.

โญ Set Options โญ

The set command takes several options (which ignore hyphens). Unambiguous option abbreviations may be used. ๐Ÿซถ

  • [no]alt-tokens โ€” turns [off] on alternative token output โ€” default is off. (Supported only in C95 and later.)
  • [no]bison-debug โ€” turns [off] on bison(1) debugging output (if it's compiled in) โ€” default is off.
  • debug[=s] โ€” turns on cdecl debugging output โ€” default is off. (Peep the --debug or -d option for the details.)
  • nodebug โ€” turns off cdecl debugging output.
  • nographs โ€” turns off either digraph or trigraph output, i.e., reverts to emitting all characters as-is.
  • digraphs โ€” turns on digraph output for [ and ] โ€” default is off. (Supported only in C95 and later.)

okay bestie the set commands keep coming, we're still going ๐Ÿ’…

  • [no]east-const โ€” this one flips on (or with the no prefix, off) "east const" output, where const (plus _Atomic and volatile bestie, the whole trio) get printed to the right โ€” aka "east" โ€” of the type. default? off. ๐Ÿซถ > heads up: this one is not supported in K&R C, so don't come crying to me.
  • [no]echo-commands โ€” turns [off] on echoing commands before their matching output, but only when you're not interactive โ€” default is off. like it's shy in interactive mode, respect it ๐Ÿ˜Œ
  • [no]english-types โ€” turns [off] on printing types in pseudo-English (think integer) instead of C/C++ (think int) whenever it's explaining gibberish โ€” default is on. so yes it's giving professor energy by default, and that's iconic โœจ
  • explicit-ecsu=s โ€” for C++ only, this turns on explicit enum, class, struct, or union in declarations โ€” default is su (that's struct and union, iykyk). (peep the --explicit-ecsu or -S option for the details.)
  • explicit-int=s โ€” turns on explicit int for the integer types s โ€” default is none. (go look at --explicit-int or -i for the full tea.)
  • noexplicit-ecsu โ€” for C++ only, this turns off explicit enum, class, struct, and union in declarations. bye girl ๐Ÿ‘‹
  • noexplicit-int โ€” turns off explicit int for all integer types. every single one. no crumbs ๐Ÿ“
  • [no]flex-debug โ€” turns [off] on flex(1) debugging output (but only if it was compiled in, so maybe it's just not there bestie ๐Ÿ™ˆ) โ€” default is off.
  • [no]infer-command โ€” turns [off] on trying to infer a command when an input line doesn't start with any โ€” default is off. (see --infer-command or -I for the deets.)
  • language=s โ€” use s (and yes it's case-insensitive, we don't gatekeep casing) as the current language. (check C AND C++ LANGUAGE VERSIONS for which languages are valid ๐Ÿ’œ)
  • lang โ€” just a shorthand for language=lang, periodt.
  • options โ€” prints the current value of all the options. the full vibe check on your config ๐ŸŒˆ
  • [no]permissive-types โ€” turns [off] on permitting keywords from language versions other than the current one to count as types โ€” default is off. (the --permissive-types or -p option has the details.)
  • [no]prompt โ€” turns [off] on the prompt โ€” default is on. she's there by default, living her main character life ๐Ÿ‘‘
  • [no]semicolon โ€” turns [off] on printing a ; at the end of a C (or C++) declaration โ€” default is on. don't forget your semicolons bestie, the compiler WILL be petty ๐Ÿ˜ญ
  • trigraphs โ€” turns on trigraph output for [, ], ^, |, and ~ โ€” default is off. (โš ๏ธ supported only between C89 and C17, and between C++03 and C++14 โ€” so it's giving vintage, don't try it elsewhere.)
  • [no]trailing-return โ€” turns [off] on declaring functions and operators using the trailing return type syntax in C++11 and later โ€” default is off.
  • [no]using โ€” turns [off] on declaring types with using rather than typedef in C++11 and later โ€” default is on. modern girl behavior, we love to see it ๐Ÿ’…
  • west-decl=s โ€” turns on printing the * for pointer, and & and && for reference types, adjacent to the type โ€” that's the "west" side โ€” and sets it to s โ€” default is r (only all return types). (the --west-decl or -w option spills the rest.)
  • nowest-decl โ€” turns off printing the * for pointer and & and && for reference types adjacent to the type (the "west" side) for all types. no asterisks near the type, we said what we said โœจ

โœจ PREDEFINED TYPES โœจ

okay so bestie, cdecl comes pre-loaded with a whole wardrobe of types ๐Ÿ’…. These are all predefined unless you pass either --no-typedefs or -t, and they show up in the language you picked and later (so C89 types are there in C99 too, yk?).

tiny plot twist ๐Ÿซฃ: the types std::partial_ordering, std::strong_ordering, and std::weak_ordering are always defined in C++20 and later, because operator<=>() literally needs them โ€” unless you give the option twice. yeah. twice. iconic behavior, no notes.

K&R C

caddr_t, daddr_t, dev_t, FILE, ino_t, jmp_buf, off_t, time_t, tm

C89

blkcnt_t, blksize_t, cc_t, clockid_t, clock_t, DIR, div_t, double_t,
errno_t, fd_set, femode_t, fenv_t, fexcept_t, float_t, fpos_t,
fsblkcnt_t, fsfilcnt_t, gid_t, iconv_t, id_t, imaxdiv_t, in_addr_t,
in_port_t, key_t, ldiv_t, lldiv_t, locale_t, long_double_t, mbstate_t,
mode_t, nfds_t, nlink_t, pid_t, posix_spawnattr_t,
posix_spawn_file_actions_t, ptrdiff_t, regex_t, regmatch_t, regoff_t,
rlim_t, sa_family_t, sig_atomic_t, sighandler_t, sigset_t, sig_t,
size_t, socklen_t, ssize_t, suseconds_t, timer_r, uid_t, useconds_t,
va_list,

_Decimal32, _Decimal32_t, _Decimal64, _Decimal64_t, _Decimal64x,
_Decimal128, _Decimal128_t, _Decimal128x,

_Float16, _Float16_t, _Float32, _Float32_t, _Float32x, _Float64,
_Float64_t, _Float64x, _Float128, _Float128_t, _Float128x

C95

pthread_t, pthread_barrier_t, pthread_barrierattr_t, pthread_cond_t,
pthread_condattr_t, pthread_key_t, pthread_mutex_t, pthread_mutexattr_t,
pthread_once_t, pthread_rwlock_t, pthread_rwlockattr_t,
pthread_spinlock_t, wctrans_t, wctype_t, wint_t,

__float80, __float128, __fp16, __ibm128, __int128, __m128, __m128d,
__m128i, __m64,

ATOM, BOOL, BOOLEAN, BYTE, CCHAR, CHAR, COLORREF, DWORD, DWORD32,
DWORD64, DWORDLONG, DWORD_PTR, FLOAT, HALF_PTR, HANDLE, HBITMAP, HBRUSH,
HCOLORSPACE, HCONV, HCONVLIST, HCURSOR, HDC, HDDEDATA, HDESK, HDROP,
HDWP, HENHMETAFILE, HFILE, HFONT, HGDIOBJ, HGLOBAL, HHOOK, HICON,
HINSTANCE, HKEY, HKL, HLOCAL, HMENU, HMETAFILE, HMODULE, HMONITOR,
HPALETTE, HPEN, HRESULT, HRGN, HRSRC, HSZ, HWINSTA, HWND, INT, _int8,
_int16, _int32, _int64, __int8, __int16, __int32, __int64, INT_PTR,
LANGID, LARGE_INTEGER, LCID, LCTYPE, LGRPID, LONG, LONG32, LONG64,
LONGLONG, LONG_PTR, LPBOOL, LPBYTE, LPCHAR, LPCOLORREF, LPCSTR, LPCTSTR,
LPCVOID, LPCWSTR, LPDWORD, LPHANDLE, LPINT, LPLONG, LPSTR, LPTSTR,
LPVOID, LPWORD, LPWSTR, LRESULT, PBOOL, PBOOLEAN, PBYTE, PCHAR, PCSTR,
PCTSTR, PCWSTR, PDWORD, PDWORD32, PDWORD64, PDWORDLONG, PDWORD_PTR,
PFLOAT, PHALF_PTR, PHANDLE, PHKEY, PINT, PINT16, PINT32, PINT64, PINT8,
PINT_PTR, PLCID, PLONG, PLONG32, PLONG64, PLONGLONG, PLONG_PTR, PSHORT,
PSIZE_T, PSSIZE_T, PSTR, PTBYTE, PTCHAR, PTSTR, PUCHAR, PUHALF_PTR,
PUINT, PUINT16, PUINT32, PUINT64, PUINT8, PUINT_PTR, PULONG, PULONG32,
PULONG64, PULONGLONG, PULONG_PTR, PUSHORT, PVOID, PWCHAR, PWORD, PWSTR,
QWORD, SC_HANDLE, SC_LOCK, SERVICE_STATUS_HANDLE, SHORT, SIZE_T,
SSIZE_T, TBYTE, TCHAR, UCHAR, UHALF_PTR, UINT, UINT16, UINT32, UINT64,
UINT8, UINT_PTR, ULARGE_INTEGER, ULONG, ULONG32, ULONG64, ULONGLONG,
ULONG_PTR, UNICODE_STRING, USHORT, USN, WCHAR, __wchar_t, WORD, WPARAM

like. that's a lot of Windows types in there. it's giving "borrowed my brother's hoodie" energy but ok we move ๐ŸŒธ

C99

int8_t, int16_t, int32_t, int64_t, intmax_t, intptr_t, uint8_t,
uint16_t, uint32_t, uint64_t, uintmax_t, uintptr_t,

int_fast8_t, int_fast16_t, int_fast32_t, int_fast64_t, int_least8_t,
int_least16_t, int_least32_t, int_least64_t, uint_fast8_t,
uint_fast16_t, uint_fast32_t, uint_fast64_t, uint_least8_t,
uint_least16_t, uint_least32_t, uint_least64_t,

int_hk_t, int_hr_t, int_k_t, int_lk_t, int_lr_t, int_r_t, uint_uhk_t,
uint_uhr_t, uint_uk_t, uint_ulk_t, uint_ulr_t, uint_ur_t

C11

atomic_bool, atomic_char16_t, atomic_char32_t, atomic_char, atomic_flag,
atomic_int, atomic_intmax_t, atomic_intptr_t, atomic_llong, atomic_long,
atomic_ptrdiff_t, atomic_schar, atomic_short, atomic_size_t,
atomic_uchar, atomic_uint, atomic_uintmax_t, atomic_uintptr_t,
atomic_ullong, atomic_ulong, atomic_ushort, atomic_wchar_t,

atomic_int_fast8_t, atomic_int_fast16_t, atomic_int_fast32_t,
atomic_int_fast64_t, atomic_int_least8_t, atomic_int_least16_t,
atomic_int_least32_t, atomic_int_least64_t, atomic_uint_fast8_t,
atomic_uint_fast16_t, atomic_uint_fast32_t, atomic_uint_fast64_t,
atomic_uint_least8_t, atomic_uint_least16_t, atomic_uint_least32_t,
atomic_uint_least64_t,

cnd_t, constraint_handler_t, max_align_t, memory_order, mtx_t,
once_flag, rsize_t, thrd_start_t, thrd_t, tss_dtor_t, tss_t

C23

nullptr_t

one. singular. the whole list is one type and honestly? main character energy ๐Ÿ‘‘

C++98

std::bad_alloc, std::bad_cast, std::bad_exception, std::bad_type_id,
std::codecvt_base, std::ctype_base, std::ctype_base::mask, std::div_t,
std::domain_error, std::exception, std::filebuf, std::fstream,
std::ifstream, std::invalid_argument, std::ios, std::ios_base::Init,
std::ios_base::event, std::ios_base::event_callback,
std::ios_base::fmtflags, std::ios_base::iostate,
std::ios_base::openmode, std::ios_base::seekdir, std::ios_base,
std::iostream, std::istream, std::istringstream, std::lconv,
std::ldiv_t, std::length_error, std::locale, std::logic_error,
std::messages_base, std::money_base, std::new_handler, std::nothrow_t,
std::ofstream, std::ostream, std::ostringstream, std::osyncstream,
std::out_of_range, std::overflow_error, std::ptrdiff_t,
std::range_error, std::runtime_error, std::sig_atomic_t, std::size_t,
std::streambuf, std::streamoff, std::streamsize, std::string,
std::stringbuf, std::stringstream, std::syncbuf, std::time_base,
std::tm, std::underflow_error, std::wfilebuf, std::wfstream,
std::wifstream, std::wios, std::wiostream, std::wistream,
std::wistringstream, std::wofstream, std::wostream, std::wostringstream,
std::wosyncstream, std::wstreambuf, std::wstring, std::wstringbuf,
std::wstringstream, std::wsyncbuf

C++11

std::atomic_bool, std::atomic_char16_t, std::atomic_char32_t,
std::atomic_char8_t, std::atomic_char, std::atomic_flag,
std::atomic_int16_t, std::atomic_int32_t, std::atomic_int64_t,
std::atomic_int8_t, std::atomic_int_fast16_t, std::atomic_int_fast32_t,
std::atomic_int_fast64_t, std::atomic_int_fast8_t, std::atomic_int,
std::atomic_int_least16_t, std::atomic_int_least32_t,
std::atomic_int_least64_t, std::atomic_int_least8_t,
std::atomic_intmax_t, std::atomic_intptr_t, std::atomic_llong,
std::atomic_long, std::atomic_ptrdiff_t, std::atomic_schar,
std::atomic_short, std::atomic_signed_lock_free, std::atomic_size_t,
std::atomic_uchar, std::atomic_uint16_t, std::atomic_uint32_t,
std::atomic_uint64_t, std::atomic_uint8_t, std::atomic_uint_fast16_t,
std::atomic_uint_fast32_t, std::atomic_uint_fast64_t,
std::atomic_uint_fast8_t, std::atomic_uint, std::atomic_uint_least16_t,
std::atomic_uint_least32_t, std::atomic_uint_least64_t,
std::atomic_uint_least8_t, std::atomic_uintmax_t, std::atomic_uintptr_t,
std::atomic_ullong, std::atomic_ulong, std::atomic_unsigned_lock_free,
std::atomic_ushort, std::atomic_wchar_t,

std::adopt_lock_t, std::allocator_arg_t, std::bad_array_new_length,
std::bad_function_call, std::bad_weak_ptr, std::bernoulli_distribution,
std::chrono::high_resolution_clock, std::chrono::steady_clock,
std::condition_variable, std::condition_variable_any, std::cv_status,
std::defer_lock_t, std::error_category, std::error_code,
std::error_condition, std::future_errc, std::future_error,
std::future_status, std::imaxdiv_t, std::ios_base::failure, std::launch,
std::lldiv_t, std::max_align_t, std::mutex, std::nullptr_t,
std::random_device, std::recursive_mutex, std::recursive_timed_mutex,
std::regex, std::regex_constants::error_type,
std::regex_constants::match_flag_type,
std::regex_constants::syntax_option_type, std::regex_error,
std::shared_mutex, std::shared_timed_mutex, std::system_error,
std::thread, std::timed_mutex, std::try_to_lock_t, std::u32string,
std::u32string_view, std::wregex

C++17

std::align_val_t, std::any, std::bad_any_cast, std::bad_optional_access,
std::bad_variant_access, std::byte, std::chars_format,
std::from_chars_result, std::memory_resource, std::mono_state,
std::string_view, std::to_chars_result, std::u16string,
std::u16string_view, std::wstring_view,

std::filesystem::copy_options, std::filesystem::directory_entry,
std::filesystem::directory_iterator, std::filesystem::directory_options,
std::filesystem::file_status, std::filesystem::file_type,
std::filesystem::filesystem_error, std::filesystem::path,
std::filesystem::perm_options, std::filesystem::perms,
std::filesystem::recursive_directory_iterator,
std::filesystem::space_info,

std::pmr::memory_resource std::pmr::monotonic_buffer_resource
std::pmr::pool_options std::pmr::synchronized_pool_resource
std::pmr::unsynchronized_pool_resource
heads up ๐Ÿซถ โ€” that last pmr chunk is listed space-separated in the original, not comma-separated. not a typo on my end, that's just how it's written. keeping it exactly as-is because we do not edit the source material around here ๐Ÿ’…

C++20

std::ambiguous_local_time, std::compare_three_way, std::endian,
std::latch, std::noop_coroutine_promise, std::strong_equality,
std::strong_ordering, std::suspend_always, std::suspend_never,
std::nonstopstate_t, std::weak_equality, std::stop_source,
std::stop_token, std::destroying_delete_t, std::format_error,
std::jthread, std::partial_ordering, std::u8string_view,
std::weak_ordering,

std::chrono::choose, std::chrono::day, std::chrono::file_clock,
std::chrono::gps_clock, std::chrono::is_clock, std::chrono::last_spec,
std::chrono::leap_second, std::chrono::local_info, std::chrono::local_t,
std::chrono::month, std::chrono::month_day, std::chrono::month_day_last,
std::chrono::month_weekday, std::chrono::month_weekday_last,
std::chrono::nonexistent_local_time, std::chrono::sys_info,
std::chrono::system_clock, std::chrono::tai_clock,
std::chrono::time_zone, std::chrono::time_zone_link, std::chrono::tzdb,
std::chrono::tzdb_list, std::chrono::utc_clock, std::chrono::weekday,
std::chrono::weekday_indexed, std::chrono::weekday_last,
std::chrono::year, std::chrono::year_month, std::chrono::year_month_day,
std::chrono::year_month_day_last, std::chrono::year_month_weekday,
std::chrono::year_month_weekday_last

the way C++20 said "here's an entire calendar" and justโ€ฆ did it ๐Ÿ—“๏ธโœจ

C++23

std::bfloat16_t, std::float128_t, std::float16_t, std::float32_t,
std::float64_t, std::ispanstream, std::ospanstream, std::range_format,
std::spanbuf, std::spanstream, std::stacktrace, std::stacktrace_entry,
std::unexpect_t, std::wispanstream std::wospanstream, std::wspanbuf,
std::wspanstream
another lil note bestie ๐Ÿ“Œ โ€” std::wispanstream and std::wospanstream are space-separated in the original too, no comma. leaving it exactly like that ๐Ÿ’–

C++26

std::hazard_pointer, std::hive_limits, std::rcu_domain, std::text_encoding,

std::contracts::assertion_kind, std::contracts::contract_violation,
std::contracts::detection_mode, std::contracts::evaluation_semantic,

std::linalg::column_major_t, std::linalg::explicit_diagonal_t,
std::linalg::implicit_unit_diagonal_t, std::linalg::lower_triangle_t,
std::linalg::row_major_t, std::linalg::upper_triangle_t

and that's the whole roster ๐ŸŽ€ โ€” future-you's C++26 types are already in the building, casually waiting for their era to start. periodt.

โœจ PREDEFINED MACROS โœจ

These are the macros that come pre-loaded, bestie โ€” they're defined in the language you picked and every version after it. So like, they just show up. Free of charge. ๐Ÿ’…

๐ŸŽ€ C89

  • __DATE__ โ€” the local date, formatted all cute like "Mmm dd yyyy".
  • __FILE__ โ€” the file name you're currently in, if there even is one; otherwise it's "stdin".
  • __LINE__ โ€” the current line number inside __FILE__, if there is one; otherwise it's just some arbitrary line number, no big deal.
  • __STDC__ โ€” it's 1. (Not defined in C++, fyi.)
  • __STDC_VERSION__ โ€” the current C version, like 202311L for C23. (Also not defined in C++.)
  • __TIME__ โ€” the local time, in the form "hh:mm:ss".

๐Ÿฆ‹ C99

  • __VA_ARGS__ โ€” the variable arguments of a macro, if it has any.

๐Ÿ’œ C++

  • __cplusplus โ€” the current C++ version, e.g. 202302L for C++23. (Not defined in C.)

๐ŸŒˆ C23 | C++20

  • __VA_OPT__ โ€” optional preprocessor tokens, wrapped up in parentheses.

๐ŸŒธ NOTES ๐ŸŒธ

๐Ÿ‘‘ main()

So in C, a function named main gets its parameters and return type checked against what main actually requires. In C++, that only happens if it's not declared const, consteval, constexpr, default, delete, final, inline, override, __restrict, static, virtual, or volatile. If it is declared with any of those, cdecl just assumes it's a member function. Periodt.

๐Ÿ“ Permissive Types

Okay so permissive types โ€” that's the --permissive-types or -p option โ€” and it is not the default, bestie. Why? Because always letting keywords from other language versions count as types can give you some genuinely confusing errors. It's giving chaos. ๐Ÿ˜ญ

Like, imagine permissive types were the default. In C you'd get this:

cdecl> declare D as virtual destructor
                    ^
14: warning: "virtual" is a keyword in C++
virtual D;
                                    ^
22: syntax error: "destructor": unexpected token ...

So what happened here: virtual isn't a keyword in C, right? So it's a totally valid name for a user-defined type. So cdecl goes "oh, a type name!" and reads the whole thing as you wanting to declare D as a variable of type virtual โ€” and it does exactly that, printing virtual D (while still warning you that virtual is a keyword in C++). But then destructor shows up out of nowhere and it's like. error. ๐Ÿ’€ And honestly? The most likely story is you just forgot to set the current language to C++ instead of C. It happens.

With the default non-permissive behavior, you get this instead:

cdecl> declare D as virtual destructor
                    ^
14: error: "virtual": unsupported keyword in C

Way clearer, right? ๐ŸŒŸ The trade-off is that it won't permit valid declarations that use keywords from language versions other than the current language as types. That's the cost, bestie. We accept it.


๐Ÿงš CONFIGURATION FILES ๐Ÿงš

A configuration file is how you set cdecl up โ€” it just runs the commands inside it on start-up. (Unless you pass --no-config or -C, in which case nope, skipped.)

The file's full path gets figured out from the first one of these that actually exists and is readable:

  1. The value of either the --config or -c option.
  2. The value of the CDECLRC environment variable.
  3. The first of these files:
~/.cdeclrc
$XDG_CONFIG_HOME/cdecl
~/.config/cdecl
  1. If the XDG_CONFIG_DIRS environment variable is set to a colon-separated list of paths, then for each path in it, the first of path/cdecl.
  2. /etc/xdg/cdecl

The commands that are actually useful inside a config file are:

  • class | define | enum | namespace | struct | typedef | union | using โ€” pre-define your own personal types so you can use them later when composing or deciphering declarations. โœจ
  • #define โ€” pre-define macros so they can be expanded later.
  • include | #include โ€” pull in other configuration files.
  • set โ€” set the language or other options for the start.

And your config files can have blank lines, C-style /* */ comments, and C++-style // comments โ€” all of those just get ignored. ๐Ÿ’–


๐Ÿ”ฅ EXAMPLES ๐Ÿ”ฅ

๐Ÿ’ซ C Declarations

Say you wanna declare an array of pointers to functions that are like malloc(3):

cdecl> declare fptab as array of pointer to function \
cdecl+     returning pointer to void
void *(*fptab[])();

And when you stumble across a declaration like that in somebody else's code and you're like "what is this", you can just:

cdecl> explain void *(*fptab[])()

The function prototype for something like _exit(2)? Declared like this:

cdecl> declare _exit as function (retval as int) returning void
void _exit(int retval);

Okay now a messier one โ€” signal(2), fully defined:

cdecl> declare signal as function \
cdecl+     (sig as int, \
cdecl+      f as pointer to function (int) returning void) \
cdecl+     returning pointer to function (int) returning void
void (*signal(int sig, void (*f)(int)))(int);

That's a lot, right? ๐Ÿ˜ญ Make it readable with one of define, typedef, or using:

cdecl> define pfi_v as pointer to function (int) returning void
cdecl> declare signal as function \
cdecl+     (sig as int, f as pfi_v) returning pfi_v
pfi_v signal(int sig, pfi_v f);

cdecl can also help you figure out where const and volatile qualifiers should go:

cdecl> declare pci as pointer to const int
const int *pci;

cdecl> declare cpi as const pointer to int
int *const cpi;

๐Ÿ’… C++ Declarations

c++decl is here to help with references:

c++decl> declare rpc as reference to pointer to char
char *&rpc;

And with pointers to members of classes:

c++decl> declare p as pointer to member of class C int
int C::*p;

and also:

c++decl> declare p as pointer to member of class C \
c++decl+     function (i as int, j as int) \
c++decl+     returning pointer to class D
D *(C::*p)(int i, int j)

To define types inside scopes:

c++decl> define A::B::T1 as int
c++decl> define T2 of scope A as int
c++decl> define T3 of scope B of scope A as int
c++decl> define T4 of scope A::B as int
c++decl> define T5 of class C::D as int
c++decl> class C { typedef int T; }
c++decl> class C1 { class C2 { typedef int T; }; }
c++decl> struct S { typedef int T; }
c++decl> namespace N { typedef int T; }
c++decl> namespace N::M { typedef int T; }
c++decl> union U { typedef int T; }

๐ŸŒŸ Preprocessor Macros

cdecl can help you understand how macros expand:

cdecl> #define NAME2_HELPER(A,B)        A ## B
cdecl> #define NAME2(A,B)               NAME2_HELPER(A,B)
cdecl> expand NAME2(var_, __LINE__)
NAME2(var_, __LINE__) => NAME2_HELPER(A,B)
| A => var_
| B => __LINE__
| | __LINE__ => 42
| B => 42
NAME2(var_, 42) => NAME2_HELPER(var_,42)
| NAME2_HELPER(var_, 42) => A ## B
| NAME2_HELPER(var_, 42) => var_ ## 42
| NAME2_HELPER(var_, 42) => var_42
NAME2(var_, 42) => var_42

โญ EXIT STATUS โญ

  • 0 โ€” Success. ๐ŸŽ‰
  • 64 โ€” Command-line usage error.
  • 65 โ€” Syntax or semantic error.
  • 66 โ€” Open file error.
  • 70 โ€” Internal software error. (Please report the bug.)
  • 71 โ€” System error.
  • 73 โ€” Create file error.
  • 74 โ€” I/O error.

๐ŸŒˆ ENVIRONMENT ๐ŸŒˆ

These are the lil environment variables that whisper sweet nothings into cdecl's ear ๐Ÿ‘‚โœจ

  • CDECL_COLORS โ€” this one decides the colors and other attributes used to highlight the various parts of the output, kinda like how GCC_COLORS works for gcc. Same energy, different tool ๐Ÿ’…

Just like with gcc, the value is a colon-separated sequence of capabilities. Each capability looks like name[=SGR], where name is a capability name and SGR โ€” if you actually put one โ€” is a "Select Graphic Rendition" value, which is itself a semicolon-separated list of integers from 0 to 255. A lil example SGR value would be 31;1, which says "bright red foreground on whatever the terminal's default background is" ๐Ÿ”ฅ

Capability names that have upper-case letters in them are cdecl-exclusive; the all-lowercase ones are upwards compatible with gcc. iykyk ๐Ÿซถ

  • caret=SGR โ€” the SGR for the caret that points at the error on the line above (same deal as gcc). Default is 32;1 (bright green foreground over the current terminal background). ๐ŸŽฏ
  • error=SGR โ€” the SGR for the word "error." Default is 31;1 (bright red foreground over current terminal background). ๐Ÿ˜ญ
  • HELP-keyword=SGR โ€” the SGR for keywords in help output. Default is 1 (bold terminal foreground over current terminal background).
  • HELP-nonterm=SGR โ€” the SGR for nonterminals in help output. Default is 36 (cyan foreground over current terminal background).
  • HELP-punct=SGR โ€” the SGR for punctuation in help output. Default is 30;1 (dark dray foreground over current terminal background). (yes, "dray" โ€” we don't make the typos, we just preserve them ๐Ÿ’€)
  • HELP-title=SGR โ€” the SGR for titles in help output. Default is 34;1 (bright blue foreground over current terminal background).
  • locus=SGR โ€” the SGR for location info in error and warning messages. Default is 1 (bold current foreground over current terminal background).
  • MACRO-no-expand=SGR โ€” the SGR for a macro that can't expand. Default is 35 (magenta foreground over current terminal background).
  • MACRO-punct=SGR โ€” the SGR for macro expansion punctuation. Default is 32;1 (bright green foreground over current terminal background).
  • MACRO-subst=SGR โ€” the SGR for macro substituted tokens. Default is 36 (cyan foreground over current terminal background).
  • PROMPT=SGR โ€” the SGR for the prompt. Default is 32 (green foreground over current terminal background).
  • warning=SGR โ€” the SGR for the word "warning." Default is 33;1 (bright yellow foreground over current terminal background). โš ๏ธ

Also, the word "color" is being used loosely here. Besides actual colors, other character attributes like bold, underlined, reverse video, etc. might be possible too โ€” it just depends on what your terminal can do. vibe check your terminal bestie ๐Ÿ–ฅ๏ธโœจ

  • CDECL_DEBUG โ€” if you set this to an "affirmative" value (one of 1, t, true, y, or yes, case-insensitive), then cdecl prints its process ID and a "waiting for debugger to attach" message to standard error, and then waits indefinitely for a debugger to attach. ๐Ÿ˜ด (It's a debugging aid for the developers of cdecl itself, so like, not for you unless you're building it.) It's only enabled when cdecl was compiled with NDEBUG not defined. ๐Ÿ› ๏ธ
  • CDECL_TEST โ€” makes testing easier. Set it to a non-empty value made of one or more of these letters (and yes, they're case-sensitive bestie):
    • c โ€” don't read any configuration file by default. You'd have to use the --config or -c option explicitly.
    • C โ€” ignore the actual terminal columns and the COLUMNS environment variable; always use 80.
    • h โ€” don't read any file under the user's home directory by default. Again, you'd have to use --config or -c explicitly.
    • m โ€” return constant values for the __DATE__, __FILE__, __LINE__, and __TIME__ macros.

You can stack multiple letters right next to each other. Or, alternatively, * means "all" and - means "none." Periodt ๐Ÿ’…

  • CDECLRC โ€” the full path to a configuration file (peep the CONFIGURATION FILES section). It's only used if it's not empty and none of the --config, -c, --no-config, or -C options were given. ๐Ÿ™ˆ
  • COLUMNS โ€” how many columns the terminal you're running cdecl in has. Used to get the terminal's width so error and warning messages can be length-limited. This takes precedence over the number of columns given by the TERM variable. ๐Ÿ“
  • HOME โ€” used to locate a default configuration file under the user's home directory. If it's unset, the home directory comes from the password database entry for the effective user. If that fails, then no default configuration file under the user's home directory gets read at all. ๐Ÿ 
  • TERM โ€” the type of terminal cdecl is being run on.
  • XDG_CONFIG_DIRS โ€” if you set this to a colon separated list of paths, then for each path in it, the first of path/cdecl to exist and be readable is used as the configuration file (see CONFIGURATION FILES). ๐Ÿ“‚
  • XDG_CONFIG_HOME โ€” if you set this to a directory path, and $XDG_CONFIG_HOME/cdecl exists and is readable, then that gets used as the configuration file (see CONFIGURATION FILES). โœจ

๐Ÿ“ FILES ๐Ÿ“

  • ~/.cdeclrc
  • $XDG_CONFIG_HOME/cdecl
  • ~/.config/cdecl
  • /etc/xdg/cdecl

โ€” all of these are the default configuration file (see CONFIGURATION FILES). ๐Ÿ—‚๏ธ

  • ~/.editrc โ€” the individual editline(3) initialization file. On systems where the readline(3) API is provided but is really just a wrapper around libedit (like macOS), the ~/.editrc file, if it's there, gets read instead of ~/.inputrc. If it's present, add this (undocumented) command:
bind ^I rl_complete

...to make tab-completion actually work in cdecl. ๐ŸŽ€

  • ~/.inputrc โ€” the individual readline(3) initialization file.

๐Ÿ› BUGS ๐Ÿ›

Readline Wrapper Around Editline

On systems where the readline(3) API is provided but is literally just a wrapper around the Editline Library (macOS, looking at you ๐Ÿ‘€), there's a few issues:

  • The wrapper has a bug that stops color prompts from working right. So the PROMPT color capability gets ignored on systems that don't provide genuine GNU readline(3). ๐Ÿšซ๐ŸŽจ
  • Hitting tab when there are no completion matches normally rings the terminal's bell. But older versions of the wrapper don't provide the rl_ding() function needed to ring that bell, so cdecl provides a substitute. Problem is, the substitute doesn't respect the user's preferred bell style (none, audible, or visual) โ€” it just always does an audible bell. ๐Ÿ””๐Ÿ˜ค
  • In some cases, hitting tab makes the wrapper suggest only a single completion instead of just inserting it. ๐Ÿ™ƒ
To dodge all of these, compile cdecl against the genuine GNU Readline Library. fr fr, it's worth it. ๐Ÿ’–

See Also

https://github.com/paul-j-lucas/cdecl/issues


๐Ÿฉธ CAVEATS ๐Ÿฉธ

okay bestie, listen. cdecl is iconic but she is not perfect and she knows it. here's the tea on what she can't do yet ๐Ÿ’…

Unsupported Declarations

these declaration types are not currently supported (not yet, anyway ๐Ÿ˜ญ):

  • only enum, class, struct, and union names and scoped type declarations are supported โ€” complete declarations are not:
struct S s;                     // supported
struct S { typedef int Int; };  // supported (C++ only)
struct S { int i; char c; } s;  // not supported
  • for array sizes, only integer literals, names, and * are supported; arbitrary expressions are not.
  • in C23 and later, auto as a storage-class specifier is no longer supported. gone girl, she left ๐Ÿฆ‹
  • for C23 typeof and typeof_unqual declarations, only types are supported; arbitrary expressions are not:
typeof(int*) x                  // supported
typeof(x) y                     // not supported
  • only C++ lambda signature declarations are supported; complete lambda declarations are not:
[n](int x)                      // supported
[n](int x) { return n * x; }    // not supported
  • C++ decltype, abbreviated function template, default argument, and template declarations are not supported. nope nope nope ๐Ÿ™ˆ
  • for C++ function exception specifications, only noexcept, noexcept(true), noexcept(false), and throw(), are supported; arbitrary expressions for noexcept or types for throw are not.
  • C++ namespace alias declarations are not supported:
namespace ALN = A_Long_Name;    // not supported
  • multiple _Alignas or alignas specifiers in the same declaration are not supported.
  • for the argument to either the _Alignas or alignas specifier, only integer literals or types are supported; arbitrary expressions are not.
  • only simple C++ attribute specifiers like [[this]] are supported; attribute specifiers with namespaces are not. additionally, optional arguments for deprecated and nodiscard are ignored.
  • C++20 contracts ([[assert]], [[ensures]], and [[expects]]) are not supported.
  • the C++20 explicit specifier with an expression is not supported.

Other Caveats

  • multi-line C-style comments can be used only on lines by themselves, or either before or after commands, but not within commands. like, pick a lane bestie ๐Ÿ’€
  • macros are expanded only via the expand command and can't be used elsewhere:
cdecl> #define exp      explain
cdecl> exp int *p           // error: can't alias commands
cdecl> #define FILE_PTR FILE*
cdecl> explain FILE_PTR f   // error: can't use as type
  • when converting from pseudo-English to a C++ declaration, any enum, class, struct, or union type keyword omitted from a declaration (via omission from either the --explicit-ecsu or -S option, or the set explicit-ecsu command) makes the declaration not "round-trippable":
c++decl> declare pt as pointer to class T
T *pt;
c++decl> explain T *pt
                 ^
18: error: "T": unknown name

this is because, when going from a C++ declaration to pseudo-English, cdecl doesn't know that an arbitrary name, in this example, T, is a class name. she's not psychic, bestie ๐Ÿ”ฎ

to include the type keywords explicitly and thus make the declarations "round-trippable," include them via either the --explicit-ecsu or -S option, or the set explicit-ecsu command.

alternatively, declare the type via one of class, define, enum, struct, typedef, union, or using:

c++decl> class T
c++decl> explain T *pt
declare pt as pointer to T
  • while class, enum, explain, namespace, struct, typedef, union, and using can accept names that are cdecl keywords, cast, declare, and define can not; hence, not all explanations are "round-trippable":
cdecl> explain int explain
declare explain as integer
cdecl> declare explain as integer
               ^
9: syntax error: "explain": name expected
  • when converting from one of the C++ overloaded operators &, *, +, ++, -, or --, to pseudo-English when declared as:
T operator OP(U);

i.e., taking one parameter, it's ambiguous (to cdecl) between being a member or non-member operator since cdecl doesn't have the context in which the operator is declared. if it were declared in-class, e.g.:

class T {
public:
    // ...
    T operator OP(U);
};

then clearly it's a member operator; if it were declared at file scope, then clearly it's a non-member operator; but cdecl doesn't have this context. in such cases, cdecl omits either member or non-member from its output. she's doing her best, okay ๐Ÿ˜ญ

  • when converting from pseudo-English to a C23 or C++11 declaration for auto (or __auto_type in GNU C), a C++17 structured binding, or a const, constinit, reference, or an rvalue reference variable that is not a function parameter, the output doesn't include an initializer:
c++decl> declare x as auto
auto x;
c++decl> declare x, y as structured binding
auto [x, y];
c++decl> declare r as reference to int
int &r;

these are illegal C++ declarations since such declarations must be initialized. oops ๐Ÿซ 

  • only casting a name is supported; casting an expression is not.
  • when converting from or to a C++ new-style cast, only some semantic validation is performed to determine whether the type of cast is legal.
  • when a predefined type, e.g., size_t, uint16_t, etc., is shown (via the show command), the underlying type is merely typical and does not necessarily match the underlying type on any particular platform or even the platform on which cdecl is running. vibes-based typing, essentially โœจ
  • an integer literal given as the argument for an alignment specifier is only checked to ensure it's either zero or a power of two; it is not checked to see whether it meets the minimum alignment for the type.
  • in GNU C, the type __int128 is a distinct type; in Microsoft C, the types __int8, __int16, __int32, __int64, and __wchar_t are keyword synonyms. these types can take modifiers:
unsigned __int128 x128;     // legal in GNU C
unsigned __int32  x32;      // legal in Microsoft C

in cdecl, these types are typedefs and can't take modifiers since that's illegal in C. rules are rules ๐Ÿšซ

  • when using the --lineno or -L option with a here document containing escaped newlines (lines ending in \), the \s also need to be escaped to get the line numbers correct because the shell ordinarily strips escaped newlines; for example:
#define IDENT_CHARS "ABCDEFGHIJKLMNOPQRSTUVWXYZ_" \\
                    "abcdefghijklmnopqrstuvwxyz" \\
                    "0123456789"

๐Ÿ‘‘ AUTHORS ๐Ÿ‘‘

cdecl has been around since the mid-1980s and there have been many versions of cdecl, some with different subsets of authors. this list is a best-effort at a union of all authors. in reverse chronological order:

Paul J. Lucas <paul@lucasmail.org> Peter Ammon <cdecl@ridiculousfish.com> David R. Conrad <conrad@detroit.freenet.org> Alexander Dupuy <dupuy@cs.columbia.edu> Merlyn LeRoy <merlyn@rose3.rosemount.com> Tony Hansen <tony@attmail.com> David Wolverton <david_wolverton@att.com> Graham Ross

legends, all of them, fr fr ๐ŸŒˆ


๐ŸŒธ SEE ALSO ๐ŸŒธ

bison(1), clang(1), flex(1), gcc(1), less(1), vi(1), yacc(1), isatty(3), readline(3), sysexits(3), editrc(5)


and that's the whole page, bestie!! ๐ŸŽ€ you made it to the end, so proud of you ๐Ÿซถ this cutie comes from the PJL TOOLS fam and the page is dated February 20, 2026 โ€” it's the cdecl(1) girlies' manual, and now you know her entirely. go declare something unhinged and slay ๐Ÿ’…๐Ÿ’–

๐Ÿ“ฆ where this page comes from