144

Very basic question: how do I write a short literal in C++?

I know the following:

  • 2 is an int
  • 2U is an unsigned int
  • 2L is a long
  • 2LL is a long long
  • 2.0f is a float
  • 2.0 is a double
  • '\2' is a char.

But how would I write a short literal? I tried 2S but that gives a compiler warning.

Kip
  • 107,154
  • 87
  • 232
  • 265
  • 15
    I guess short literal is not supported solely due to the fact that anything less than int will be "promoted" to int during evaluation. int has the most natural size. This is called integer promotion in C++. – user534498 Feb 16 '11 at 05:49

7 Answers7

99
((short)2)

Yeah, it's not strictly a short literal, more of a casted-int, but the behaviour is the same and I think there isn't a direct way of doing it.

That's what I've been doing because I couldn't find anything about it. I would guess that the compiler would be smart enough to compile this as if it's a short literal (i.e. it wouldn't actually allocate an int and then cast it every time).

The following illustrates how much you should worry about this:

a = 2L;
b = 2.0;
c = (short)2;
d = '\2';

Compile -> disassemble ->

movl    $2, _a
movl    $2, _b
movl    $2, _c
movl    $2, _d
Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
  • That's what I've been doing because I couldn't find anything about it. I would guess that the compiler would be smart enough to compile this as if it's a short literal (i.e. it wouldn't actually allocate an int and then cast it every time). – Kip Oct 16 '08 at 13:25
  • 1
    The "cast" is not really doing anything. There is no "cast" assembler instruction when we're talking C or C++ (.NET MSIL is a different story though). There on the metal, it's all just binary digits – Isak Savo Oct 16 '08 at 13:47
  • 15
    What are the types of a,b,c and d above? – Ates Goral Oct 16 '08 at 16:30
  • 2
    @Ates Goral: All ints. Changing to short or char would presumably change the instruction to movw or movb across the board. –  Oct 16 '08 at 18:11
  • 3
    That's no short literal. When you use that cast and compile with GCC and the option -Wconversion you still get a compiler diagnostic for the statement `short foo = 1; foo += (short)2;`. But this can't be circumvented due to the integer promotion. – harper Jan 27 '14 at 11:44
  • I love the assembler demonstration. – Peter - Reinstate Monica Sep 02 '19 at 20:05
  • `short(2)` is a bit more readable, as @jimvonmoon points out, though `((short)2)` has the advantage of working in both C and C++. – Pablo Halpern Dec 14 '20 at 21:44
  • 1
    How much optimization did you compile with? – Spencer Oct 12 '21 at 14:12
55

C++11 gives you pretty close to what you want. (Search for "user-defined literals" to learn more.)

#include <cstdint>

inline std::uint16_t operator "" _u(unsigned long long value)
{
    return static_cast<std::uint16_t>(value);
}

void func(std::uint32_t value); // 1
void func(std::uint16_t value); // 2

func(0x1234U); // calls 1
func(0x1234_u); // calls 2

// also
inline std::int16_t operator "" _s(unsigned long long value)
{
    return static_cast<std::int16_t>(value);
}
DavidRR
  • 18,291
  • 25
  • 109
  • 191
Ken Smith
  • 775
  • 5
  • 11
  • 11
    `short` physically cannot be an `std::uint`anything, as it is a signed type. And it is not required to be either 16 bits or the same type as an `std::int16_t`... which itself is not even required to _exist_ in a given implementation if the platform cannot supply the exact-width type. The core idea of this answer is good, but it's devalued by the inexplicable tangent into unrelated types that the OP didn't ask about. – underscore_d Aug 18 '16 at 12:26
  • Note user-defined literals are not supported in Visual Studio until VS2015: https://msdn.microsoft.com/en-us/library/hh567368(v=vs.140).aspx – parsley72 Oct 04 '17 at 19:35
  • I don't know whether I should love or hate it but this is the last piece to my actually *Strong* integer type system in C++ that I'm working on, it's amazing. –  Dec 04 '19 at 16:26
  • echoing @underscore_d, I would upvote but after an edit to `short` as aked by OP. – v.oddou May 29 '20 at 06:36
  • Don't know why this is upvoted so much, to my understanding this just won't work with a signed type properly. C++ just does not support it. Only `unsigned long long int` is supported as integer argument. – lars Nov 25 '20 at 12:44
  • 1
    @lars, it does work with signed types. An `unsigned long long int` containing a value known to fit within a short will convert just fine. There are all sort of compile-time and runtime checks that could and should be added to ensure that the value is in range, the this code absolutely does work. Note that there are no signed literals in C++; the expression `-42` is actually the literal `42` preceded by the negation operator. Thus in Ken's example `-42_s` would produce the equivalent of `-static_cast(42ULL)`, which is an `int16_t` with value `-42`. – Pablo Halpern Dec 14 '20 at 21:39
  • Thanks, i made some wrong conclusion by "there are no signed literals". – lars Dec 15 '20 at 13:41
  • You want to make these "constexpr" not "inline"- – Silicomancer Sep 01 '22 at 07:55
35

Even the writers of the C99 standard got caught out by this. This is a snippet from Danny Smith's public domain stdint.h implementation:

/* 7.18.4.1  Macros for minimum-width integer constants

    Accoding to Douglas Gwyn <gwyn@arl.mil>:
    "This spec was changed in ISO/IEC 9899:1999 TC1; in ISO/IEC
    9899:1999 as initially published, the expansion was required
    to be an integer constant of precisely matching type, which
    is impossible to accomplish for the shorter types on most
    platforms, because C99 provides no standard way to designate
    an integer constant with width less than that of type int.
    TC1 changed this to require just an integer constant
    *expression* with *promoted* type."
*/
Michael Burr
  • 333,147
  • 50
  • 533
  • 760
29

Disclaimer: I'm leaving this answer up as a curiosity, but you really shouldn't be using this in production code. Use UDL or constants of the appropriate types instead.


If you use Microsoft Visual C++, there are literal suffixes available for every integer type:

auto var1 = 10i8;  // char
auto var2 = 10ui8; // unsigned char

auto var3 = 10i16;  // short
auto var4 = 10ui16; // unsigned short

auto var5 = 10i32;  // int
auto var6 = 10ui32; // unsigned int

auto var7 = 10i64;  // long long
auto var8 = 10ui64; // unsigned long long

Note that these are a non-standard extension and aren't portable. In fact, I couldn't even locate any info on these suffixes on MSDN.

Alexander Revo
  • 719
  • 9
  • 15
  • 1
    When you trace one of the suffixes, you'll see that e.g. `""ui8` is defined as `'\000'`, which is essentially `'\0'`. – Nikita Jan 28 '17 at 19:03
13

You can also use pseudo constructor syntax.

short(2)

I find it more readable than casting.

jimvonmoon
  • 342
  • 3
  • 12
  • 7
    it's called a "functional cast expression". I like it very much as well, especially when programming with the Windows API. – klaus triendl Feb 22 '17 at 09:18
9

One possibility is to use C++11 "list initialization" for this purpose, e.g.:

short{42};

The advantage of this solution (compared to a cast as in the currently accepted answer) is that it does not allow narrowing conversions:

auto number1 = short(100000); // Oops: Stores -31072, you may get a warning
auto number2 = short{100000}; // Compiler error. Value too large for type short

See https://en.cppreference.com/w/cpp/language/list_initialization#Narrowing_conversions for prohibited narrowing conversions with list-init

P. Saladin
  • 211
  • 2
  • 6
  • I haven't done C/C++ in quite a while. Could you use this like `short mynum = short{42};` ? – Kip Nov 30 '20 at 22:16
  • 1
    @Kip You can, but I usually use `short variable{123}` to declare and initialize a variable. The form `short{123}` is useful e.g. when you just need a short (or whatever type) number but have no variable to assign it. This e.g. happens frequently to me in unit test asserts, where you need to provide not only the expected value but also the expected type. – P. Saladin Dec 01 '20 at 16:34
8

As far as I know, you don't, there's no such suffix. Most compilers will warn if an integer literal is too large to fit in whatever variable you're trying to store it in, though.

unwind
  • 391,730
  • 64
  • 469
  • 606