unsigned 关键字可以以非显而易见的方式使用吗?
每次我使用 unsigned
关键字时,它都会出现在 int
或其他内置类型之前。 我想知道是否还有其他方式可以使用unsigned
。
- 用户定义的类型(类/结构)可以使用
unsigned
关键字吗? - 模板可以特殊使用
unsigned
吗?
如果不是,为什么它有自己的关键字?为什么unsigned int
不是uint
?
Every time I've used the unsigned
keyword it has been before int
, or another built-in type. I was wondering if there were any other ways unsigned
could be used.
- Can user defined types (classes/structs) use the
unsigned
keyword? - Can templates make special use with
unsigned
?
If not, why does it have its own keyword? Why is unsigned int
not uint
?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
主要问题已经回答了好几次:
unsigned
关键字只能用作整型的类型说明符。至于为什么
unsigned
是一个单独的关键字,而不是一个uint
关键字,其原因是历史性的。C 的最早版本(K&R 之前)只有四种基本类型:
char
(8 位,有符号,2 的补码)int
(16 位,有符号, 2 的补码)float
(32 位)double
(64 位,与float
范围相同,但精度更高)注意缺少什么:否
signed
或unsigned
关键字,无short
、long
或long double
;所有这些都是后来添加的。 (需要无符号算术的程序员通常使用指针,它们可以与 int 自由互换。)每个基本类型都有一个作为单个关键字的名称,这使得语法简单明了。
当后来添加其他类型时,将
unsigned
、short
和long
等说明符添加到现有类型名称中而不是引入新的类型是有意义的关键字(可能会破坏现有代码)。当 ANSI C 委员会于 1989 年对该语言进行标准化时,他们必须根据现有的不太正式的定义制定一个连贯的结构,同时与现有的实现保持一致。结果就是我们现在所看到的,其中int long unsigned long
是一个有效的类型名称(更常见地写为unsigned long long
)。如果现在从头开始设计该语言,我怀疑会采取不同的方法。也许每个基本类型都有一个关键字(例如,C# 采用的方法),或者基本类型名称可能会使用一些更连贯的方案,而不是一堆关键字(例如,
int:2
表示 2 字节整数,unsigned:4
表示 4 字节无符号整数)。但 C 和 C++ 都坚持当前的方法。参考:http://cm.bell-labs.com/cm /cs/who/dmr/cman.pdf
The main question has been answered several times: the
unsigned
keyword can only be used as a type-specifier for an integral type.As for why
unsigned
is a separate keyword, rather than having, say, auint
keyword, the reasons for that are historical.The earliest versions of C (pre-K&R) had only four fundamental types:
char
(8 bits, signed, 2's-complement)int
(16 bits, signed, 2's-complement)float
(32 bits)double
(64 bits, same range asfloat
but greater precision)Note what's missing: no
signed
orunsigned
keywords, noshort
,long
, orlong double
; all those were added later. (Programmers who needed unsigned arithmetic commonly used pointers, which were freely interchangeable withint
.)Each fundamental type had a name that was a single keyword, which made the grammar straightforward.
When other types were added later, it made sense to add specifiers like
unsigned
,short
, andlong
to the existing type names rather than introducing new keywords (which might have broken existing code). When the ANSI C committee standardized the language in 1989, they had to make a coherent structure out of the existing not-quite-formal definitions while remaining consistent with existing implementations. The result is what we have now, whereint long unsigned long
is a valid type name (more commonly written asunsigned long long
).If the language were being designed from scratch now, I suspect that a different approach would have been taken. Perhaps there would be a single keyword for each fundamental type (that's the approach taken by C#, for example), or perhaps the fundamental type names would use some more coherent scheme rather than a jumble of keywords (say,
int:2
for a 2-byte integer,unsigned:4
for a 4-byte unsigned integer). But both C and C++ are stuck with the current approach.Reference: http://cm.bell-labs.com/cm/cs/who/dmr/cman.pdf
不,它不能与类或结构一起使用,因为它们不是整型。模板所能做的就是使 int 成为无符号的。我认为它被选为一个单独的关键字,因为它可以应用于任何整数类型(char、int、long、long long),从而用一个关键字实现需要四个关键字的效果。它的含义也很明显,而 uint、uchar 等则不一定。请记住,它也可以在没有限定符的情况下单独使用,在这种情况下,假定为 unsigned int。
No, it can't be used with classes or structs since they're not integral types. All a template can do with it is make an int unsigned. I think it was chosen as a separate keyword since it can be applied to any integer type (char, int, long, long long), thereby achieving with one keyword what would have required four more. Its meaning is also immediately evident, whereas uint, uchar, etc. aren't necessarily. And keep in mind it can also be used by itself without a qualifier, in which case unsigned int is assumed.
unsigned
是一个关键字。unsigned
只能用于整型 类型。unsigned
或signed
被视为类型说明符,简单类型说明符。所以他们指定类型要么是有符号的,要么是无符号的。您可以通过 typedef 将单词 unsigned int 转换为 uint,但是当
int
为类型和unsigned
本身就是类型说明符。与普遍看法相反,您可以单独使用
unsigned
,如 C++ ISO 标准第 7.1.5.2 节表 7 所示:您可以使用多个类型说明符(仅在允许时),并且可以按任何顺序与 decl 说明符自由混合。
您也可以这样做:
这是有效的 C++。
unsigned
is a keyword.unsigned
can only be used on integral types.unsigned
orsigned
is considered a type-specifier, a simple type-specifier. So they specify that the type will either by signed or unsigned.You can
typedef
the wordsunsigned int
touint
but then that would make it look like a type whenint
is the type andunsigned
is the type-specifier per se.You can use
unsigned
by itself, contrary to popular belief, as evidenced in the C++ ISO Standard Section 7.1.5.2 Table 7:You can use multiple type-specifiers (when only allowed) and can be freely mixed with decl-specifiers in any order.
You can also do this:
and this is valid C++.
No unsigned 本身并不是一个真正的关键字;它只是 int、short、char 的修饰符。unsigned
关键字可以用作int
、short
、char
或long
。它也可以单独用作类型名称;unsigned
表示unsigned int
。这样做是为了避免使用三个额外的关键字 uint ushort uchar 并且因为在 C 和 Unix 所针对的所有早期计算机上有符号/无符号可能没有不同。
No unsigned isn't really a keyword on its own; it's only a modifier for int, short, char.The
unsigned
keyword can be used as a modifier forint
,short
,char
, orlong
. It can also be used on its own as a type name;unsigned
meansunsigned int
.It was done that way to avoid having three extra keywords uint ushort uchar and because signed/unsigned might not have been different on all the early computers C and Unix were aimed at.
关键字signed、unsigned、short 和long 是类型修饰符/说明符,当这些类型修饰符/说明符之一单独使用时,假定数据类型为int。
因此,signed 和 unsigned 也可以
用作独立类型说明符
,分别与signed int 和unsigned int 含义相同。以下两个声明是等效的:The keywords signed, unsigned, short, and long are type modifiers/specifier and When one of these type modifiers/specifier is used by itself, a data type of int is assumed.
So signed and unsigned may also be
used as standalone type specifiers
, meaning the same as signed int and unsigned int respectively. The following two declarations are equivalent:还有无符号字符。有些编译器,例如 GNU 的 g++,允许您只输入 unsigned 并假设您的意思是 unsigned int。例如以下代码是等效的
There is also unsigned char. Some compilers, such as GNU's g++, let you just put unsigned and assume you mean unsigned int. For example the following code is equivalent
SerenityOS 有一篇博客文章介绍了如何将
unsigned
重新定义为signed
,以在标头中实现size_t
:https://awesomekling.github.io/How-SerenityOS-declares-ssize_t/这可能看起来很黑客,但如果你只支持 GCC/Clang),它们是唯一实现
的编译器__SIZE_TYPE__
,并且需要在没有任何系统库的情况下独立编译(就像内核的情况一样),那么这种定义 ssize_t 的方法是可靠的,而且更可靠比令人讨厌的#ifdef迷宫更容易维护。为了参考和好奇,让我们研究一下
ssize_t
通常如何/何时在我的 x86_64 Linux Mint 机器上定义。ssize_t
可以在许多不同的地方按需定义,例如定义__USE_XOPEN2K8
时的
(旧旧遗留)东西)。但是,ssize_t
定义的主要位置是/usr/include/x86_64-linux-gnu/sys/types.h
的第 107-110 行,通常将其带入通过包含
。以下是第 107-110 行:__ssize_t
来自/usr/include/x86_64-linux-gnu/bits/types.h
的第 193 行:__SSIZE_T_TYPE
来自/usr/include/x86_64-linux-gnu/bits/typesizes.h
第 73 行:__SWORD_TYPE
来自/usr/include/x86_64-linux-gnu/bits/types.h
的第 115-114 行:__WORDSIZE
来自从/usr/include/x86_64-linux-gnu/bits/wordsize.h
第 3-9 行:
__x86_64__
和__ILP32__
都是编译器提供的预定义宏,并从根据源代码构建编译器的 makefile 中烘焙到编译器的二进制文件中。/usr/include/x86_64-linux-gnu
下的所有文件都特定于我的计算机的本机 x86_64 架构,并且 x86_64 专门是 x86 ABI 的 SysV 64 位扩展。检查
定义的 __x86_64__ &&仅当将 x86_64 编译器与
才为 false 。然而,编译 32 位二进制文件的更常见方法是安装相应的 GCC 多架构编译器。-m32
或-mx32
一起使用以强制其分别生成 32 位或 x32-abi 代码时,!define __ILP32__为了进行比较,musl libc 采用更短的路径,仅在特定于体系结构的标头基础上将所有类型定义为其各自的固定宽度整数。对于 x86_64: https://git.musl-libc.org/cgit/musl/tree/arch/x86_64/bits/stdint.h?id=3f08154ac494f4739afbc7451f317b2ef1bffbd3
SerenityOS has a blog post about how they redefine
unsigned
tosigned
briefly to implementsize_t
in their headers: https://awesomekling.github.io/How-SerenityOS-declares-ssize_t/This may look hackish but if you are only supporting GCC/Clang), which are the only compilers to implement
__SIZE_TYPE__
, and need to compile freestanding without any system libraries (as is the case for kernels), then this approach to definingssize_t
is solid, reliable, and far more maintainable than a nasty maze of#ifdef
s.For reference and curiosity, let's investigate how/when
ssize_t
is normally defined on my x86_64 Linux Mint machine.ssize_t
can be defined on-demand in a number of different places such as<stdio.h>
when__USE_XOPEN2K8
is defined (old old legacy stuff). BUT, the primary placessize_t
is defined is on lines 107-110 of/usr/include/x86_64-linux-gnu/sys/types.h
, which is typically brought in by including<unistd.h>
. Here are lines 107-110:The
__ssize_t
comes from line 193 of/usr/include/x86_64-linux-gnu/bits/types.h
:The
__SSIZE_T_TYPE
comes from line 73 of/usr/include/x86_64-linux-gnu/bits/typesizes.h
:The
__SWORD_TYPE
comes from lines 115-114 of/usr/include/x86_64-linux-gnu/bits/types.h
:The
__WORDSIZE
comes from lines 3-9 of/usr/include/x86_64-linux-gnu/bits/wordsize.h
:The
__x86_64__
and__ILP32__
are both predefined macros provided by the compiler and baked into the compiler's binary from the makefile that built it from its source code.All files under
/usr/include/x86_64-linux-gnu
are specific to the native x86_64 architecture of my computer, and x86_64 is exclusively the SysV 64-bit extension of the x86 ABI.The check for
defined __x86_64__ && !defined __ILP32__
is only false if using the x86_64 compiler with-m32
or-mx32
to force it to generate 32-bit or x32-abi code, respectively. However, the more common approach to compile 32-bit binaries is to install the respective GCC multiarch compiler.For comparison, musl libc takes a much shorter rout and just defines all the types to their respective fixed-width integers on an architecture-specific-header basis. For x86_64: https://git.musl-libc.org/cgit/musl/tree/arch/x86_64/bits/stdint.h?id=3f08154ac494f4739afbc7451f317b2ef1bffbd3