如果char
在C(使用gcc)中签名或未签名,会导致什么?我知道,标准并没有规定一个比其他,我也可以检查CHAR_MIN
,并CHAR_MAX
从limits.h中,但我想知道是什么原因引发了另一种使用GCC时
如果我从libgcc-6读取limits.h,我看到有一个宏__CHAR_UNSIGNED__
定义了一个"默认"char签名或无符号但我不确定这是由编译器在(他)的构建时间设置的.
我试图列出GCC预定义的makros
$ gcc -dM -E -x c /dev/null | grep -i CHAR
#define __UINT_LEAST8_TYPE__ unsigned char
#define __CHAR_BIT__ 8
#define __WCHAR_MAX__ 0x7fffffff
#define __GCC_ATOMIC_CHAR_LOCK_FREE 2
#define __GCC_ATOMIC_CHAR32_T_LOCK_FREE 2
#define __SCHAR_MAX__ 0x7f
#define __WCHAR_MIN__ (-__WCHAR_MAX__ - 1)
#define __UINT8_TYPE__ unsigned char
#define __INT8_TYPE__ signed char
#define __GCC_ATOMIC_WCHAR_T_LOCK_FREE 2
#define __CHAR16_TYPE__ short unsigned int
#define __INT_LEAST8_TYPE__ signed char
#define __WCHAR_TYPE__ int
#define __GCC_ATOMIC_CHAR16_T_LOCK_FREE 2
#define __SIZEOF_WCHAR_T__ 4
#define __INT_FAST8_TYPE__ signed char
#define __CHAR32_TYPE__ unsigned int
#define __UINT_FAST8_TYPE__ unsigned char
Run Code Online (Sandbox Code Playgroud)
但是找不到 __CHAR_UNSIGNED__
背景:我有一些代码可以在两台不同的机器上编译:
桌上型电脑:
char
签了覆盆子Pi3:
char
没有签名所以唯一明显的区别是CPU架构......
Bas*_*tch 52
根据C11标准(读n1570),char
可以是signed
或unsigned
(所以你实际上有两种口味的C).究竟是什么具体的实施.
一些处理器和指令集体系结构或应用程序二进制接口支持signed
字符(字节)类型(例如,因为它很好地映射到某些机器代码指令),而另一些支持unsigned
一个.
gcc
除非你重新编译所有东西,包括你的C标准库,否则你甚至应该使用一些-fsigned-char
或几乎不会使用的-funsigned-char
选项(因为更改它会破坏调用约定和ABI中的一些极端情况).
您可以在Linux上使用feature_test_macros(7)和<endian.h>
(请参阅endian(3))或autoconf来检测系统的内容.
在大多数情况下,您应该编写可移植的 C代码,它不依赖于这些东西.您可以找到跨平台库(例如glib)来帮助您.
BTW gcc -dM -E -x c /dev/null
也给出了__BYTE_ORDER__
等等,如果你想要一个无符号的8位字节,你应该使用<stdint.h>
它uint8_t
(更便携,更可读).和标准limits.h中定义CHAR_MIN
和SCHAR_MIN
和CHAR_MAX
和SCHAR_MAX
(你可以比较它们是否相等检测signed char
小号实现),等等.
顺便说一下,你应该关心字符编码,但是现在大多数系统都使用UTF-8.像libunistring这样的库很有帮助.另请参阅此内容并记住,实际上,以UTF-8编码的Unicode字符可以跨越几个字节(即-s).char
Jon*_*ler 42
默认值取决于平台和本机代码集.例如,使用EBCDIC(通常是大型机)的机器必须使用unsigned char
(或拥有CHAR_BIT > 8
),因为C标准要求基本代码集中的字符为正,而EBCDIC使用240代码来代表数字0.(C11标准,§6.2.5 类型 2说:声明为类型的对象char
足以存储基本执行字符集的任何成员.如果基本执行字符集的成员存储在char
对象中,则其值保证为非负.)
您可以控制GCC使用的标志-fsigned-char
或-funsigned-char
选项.这是一个好主意是一个单独的讨论.
至少在x86-64 Linux上,它由x86-64 System V psABI定义
其他平台将具有类似的ABI标准文档,这些文档指定了允许不同C编译器在调用约定,结构布局和类似内容上彼此一致的规则.(有关其他x86 ABI文档的链接或其他体系结构的其他位置,请参阅x86标记wiki.大多数非x86体系结构只有一个或两个标准ABI.)
来自x86-64 SysV ABI:图3.1:标量类型
Run Code Online (Sandbox Code Playgroud)C sizeof Alignment AMD64 (bytes) Architecture _Bool* 1 1 boolean ----------------------------------------------------------- char 1 1 signed byte signed char --------------------------------------------------------- unsigned char 1 1 unsigned byte ---------------------------------------------------------- ... ----------------------------------------------------------- int 4 4 signed fourbyte signed int enum*** ----------------------------------------------------------- unsigned int 4 4 unsigned fourbyte -------------------------------------------------------------- ...
*此类型
bool
在C++中调用.***C++和C的一些实现允许枚举大于int.底层类型按顺序碰撞到unsigned int,long int或unsigned long int.
char
在这种情况下,是否签名实际上直接影响调用约定,因为clang依赖于当前未记录的需求: 根据被调用者原型,当作为函数args传递时,narrow类型符号或零扩展为32位.
因此 int foo(char c) { return c; }
,clang将依赖调用者对arg进行符号扩展.(代码+ asm为此和Godbolt上的调用者).
gcc:
movsx eax, dil # sign-extend low byte of first arg reg into eax
ret
clang:
mov eax, edi # copy whole 32-bit reg
ret
Run Code Online (Sandbox Code Playgroud)
即使除了调用约定之外,C编译器也必须同意,因此它们.h
以相同的方式编译内联函数.
如果(int)(char)x
在同一平台的不同编译器中表现不同,它们就不会真正兼容.
gcc有两个编译时选项来控制以下行为char
:
-funsigned-char
-fsigned-char
Run Code Online (Sandbox Code Playgroud)
除非您确切知道自己在做什么,否则不建议使用任何这些选项.
默认值取决于平台,并在构建gcc时固定.选择它是为了与该平台上存在的其他工具的最佳兼容性.
来源.
归档时间: |
|
查看次数: |
5914 次 |
最近记录: |