如何编写无符号短整型字面值?

56
无符号整数42可以用"42U"来明确定义。
unsigned int foo = 42U; // yeah!

如何清晰地表示一个无符号短整型变量"23"?
unsigned short bar = 23; // booh! not clear!

将英文文本翻译为中文:

编辑以使问题的含义更清晰:

template <class T>
void doSomething(T) {
    std::cout << "unknown type" << std::endl;
}

template<>
void doSomething(unsigned int) {
    std::cout << "unsigned int" << std::endl;
}

template<>
void doSomething(unsigned short) {
    std::cout << "unsigned short" << std::endl;
}

int main(int argc, char* argv[])
{
    doSomething(42U);
    doSomething((unsigned short)23); // no other option than a cast?

    return EXIT_SUCCESS;
}

2
声明一个名字合适的 'const unsigned short' 对象,然后在代码中使用它来代替数字 23。这样做虽然不能明确表明数字 23 是无符号短整型,但至少你只需要检查该声明以确保正确性。其他地方都将使用该常量,因此含义将变得清晰明了。 - Richard Corden
@Richard Corden:这是用于数百次作为单元测试的输入值和结果,所以越短越好... U代表无符号整数很方便,但是(unsigned short)强制转换或const unsigned short对象令人恼火。 - moala
你正在询问如何声明一个无符号短整型字面量。如果你搜索这个问题,你会找到答案的。正如已经说过的,你不能这样做。 - deft_code
10个回答

47
你不能这样做。数字字面量不能使用shortunsigned short类型。

当然,为了赋值给bar,文本的值会被隐式转换为unsigned short。在你的第一个代码示例中,你可以使用转换显式地进行转换,但我认为很明显将会发生什么转换。使用强制类型转换可能更糟糕,因为在某些编译器中,如果文本值超出了unsigned short的范围,则将抑制任何警告。不过,如果你有好的理由想要使用这种值,那么抑制警告是有益的。

在你所修改的例子中,这是一个模板函数而不是重载函数,你有一种替代方案可以避免使用转换:do_something<unsigned short>(23)。对于重载函数,你仍然可以避免使用转换:
void (*f)(unsigned short) = &do_something;
f(23);

...但我不建议这样做。如果没有其他选择,这只在unsigned short版本实际存在时才能起作用,而使用强制类型转换的调用则执行通常的重载解析以找到可用的最兼容版本。


15
unsigned short bar = (unsigned short) 23;

或者用新的说法来说...

unsigned short bar = static_cast<unsigned short>(23);

3
这在 C 中是正确的做法,但我记得在 C++ 中不推荐使用 C 式转换。 - starblue
7
不受欢迎!也许我已经修订了一个最新版本来让你满意! - AnthonyLambert

7

至少在Visual Studio(至少2013年及以上版本)中,您可以编写以下内容:

23ui16

获取无符号短整型常量的方法:

请查看stdint.h文件中INT8_MIN、INT8_MAX、INT16_MIN、INT16_MAX等宏定义的含义。

目前我不确定这是否属于标准C/C++。


1
那是一个Visual Studio扩展。它不是标准C的一部分。你可以使用“用户字面量”功能在标准C++11中为自己实现它,正如https://dev59.com/f5Dea4cB1Zd3GeqPjf8v所指出的那样。 - user7610

2

无符号短整型没有修饰符。通常情况下,整型默认为 int 类型,并且通常可以隐式转换为目标类型。但是如果您确实想显式指定类型,则可以编写以下内容:

unsigned short bar = static_cast<unsigned short>(23);

我所能看到的唯一原因是使用这种指示来正确推断模板类型:

func( static_cast<unsigned short>(23) );

但是对于这种情况,更清晰的调用方式应该是以下这样:

func<unsigned short>( 23 );

2
这里有多个答案,但都不是很令人满意。因此,以下是一个汇编答案,并附加一些信息以更全面地解释问题。
首先,避免使用shorts,但如果你发现自己需要它们,例如在使用索引网格数据时,切换到shorts以减小索引数据大小的两倍...那么请继续阅读...
1. 尽管在c或C++中无法表示无符号短文字面量,但你可以通过在字面量前加上'u'来轻松规避这个限制。
unsigned short myushort = 16u;

这段代码之所以有效,是因为它告诉编译器16是无符号整数,然后编译器寻找将其转换为无符号短整型的方法,找到了一个方法,大多数编译器会检查溢出情况,并且在不报错的情况下进行转换。当省略“u”时,“缩小转换”错误/警告表示代码正在抛弃符号,如果文字是负数(如-1),则结果是未定义的。通常这意味着你将得到一个非常大的无符号值,然后被截断以适应短整型。
2.有多种建议可以避开这个限制,大多数经验丰富的程序员会总结出一个“不要那样做”。
unsigned short myshort = (unsigned short)16;
unsigned short myothershort = static_cast<unsigned short>(16);

虽然这两种方法都能实现,但它们有两个主要问题。首先,它们冗长,程序员很懒,为了一个字面量而输入这么多内容容易被忽略,这会导致本可以通过更好的解决方案避免的基本错误。其次,它们不是免费的,特别是static_cast生成一些汇编代码来进行转换,虽然优化器可能(或可能不)能够发现它可以进行转换,但最好从一开始就编写高质量的代码。
unsigned short myshort = 16ui16;

这种解决方案是不可取的,因为它限制了能够阅读和理解你代码的人,并且意味着你正在踏上编译器特定代码的滑坡,这可能会导致你的代码突然失效,因为某些编译器作者的奇 whims 怪想法,或者某些公司随意地“右转”,或者离开而让你陷入困境。
unsigned short bar = L'\x17';

这篇文章太难懂了,没有人点赞。而且由于很多好的原因,应该避免使用难以理解的语言。

unsigned short bar = 0xf;

这段文字较难读懂。虽然能够读懂并转换十六进制是程序员必须学习的技能,但它很快变得难以阅读。现在问一下,这个数字是多少:0xbad? 现在将其转换为二进制…现在是八进制。

最后,如果您认为以上所有解决方案都不可行,我提供了另一种通过用户定义运算符可用的解决方案。

constexpr unsigned short operator ""_ushort(unsigned long long x) 
{ 
    return (unsigned short)x; 
}

并且使用它

unsigned short x = 16_ushort;

不可否认,这也不是完美的。首先它需要一个unsigned long long,并将其全部转换为unsigned short,在此过程中抑制潜在的编译器警告,并使用c风格的转换。但它是constexpr的,保证在优化后的程序中是免费的,但在调试期间可以逐步执行。它也很简短,程序员更有可能使用它,而且表达力强,易于阅读和理解。不幸的是,它需要一个最近的编译器,因为C++的各个版本中可以合法地使用用户定义的运算符已经发生了变化。

所以选择你的权衡,但要小心,因为你可能会后悔。祝您编程愉快。


0
在C++11及其后续版本中,如果您真的想要一个无符号短整型字面量转换,那么可以使用用户自定义字面量来实现:
using uint16 = unsigned short;
using uint64 = unsigned long long;

constexpr uint16 operator""_u16(uint64 to_short) {
    // use your favorite value validation
    assert(to_short < USHRT_MAX); // USHRT_MAX from limits.h
    return static_cast<uint16>(to_short);
}


int main(void) {
  uint16 val = 26_u16;
}

0

很遗憾,这个的唯一定义方法是

单引号中的一个或两个字符 ('), 前面加上字母 L

根据 http://cpp.comsci.us/etymology/literals.html 的说法

这意味着您必须将数字表示为 ASCII 转义序列:

unsigned short bar = L'\x17';

5
您的文字将具有类型 wchar_t。您引用的来源是错误的。 - avakar
感谢您的纠正。我会保留这个答案,以防其他人被那个链接误导(它在明显的谷歌搜索结果中出现,就像我的情况一样)。 - Tyler McHenry
1
它还有更多的问题,比如假设ASCII码。'A'并不总是65。 - MSalters

0

很遗憾,他们不能。但是如果人们只是看数字后面的两个单词,他们应该清楚地看到这是一个简短的... 它并不是那么模棱两可。但这样做会很好。


如果一个方法对于无符号整数和无符号短整型的行为不同,并且您以 doThings(42U) 方式传递它,则这是有歧义的。除了 doThings((unsigned short)23) 之外还有其他方法吗? - moala

0
如果您将数量表示为4位十六进制数,则无符号短整型可能更清晰。 unsigned short bar = 0x0017;

2
0x0017 作为无符号短整型对于读者可能很清晰,但对于编译器来说却不一定清晰。 - moala

0

如果你没有大量使用short,那么最好不要使用它。它的目的是比int占用更少的存储空间,但是int将具有架构的“自然大小”。逻辑上讲,short可能不具备这个特性。与位域类似,这意味着short可以被视为一种时空权衡。只有在它能够节省大量空间时才值得使用。然而,在你的应用程序中,很少会有很多字面量,因此没有必要使用short字面量。这些用例根本没有重叠。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接