讨论个 c 语言char 的问题

中山野鬼 发布于 2013/08/25 19:44
阅读 1K+
收藏 3

char 这个类型很古怪。哈。如果

int main(int argc ,char *argv[])

写成如下两种形式,编译器都会有警告。

int main(int argc,signed char *argv[])

int main(int argc,unsigned char *argv[])

这个事情,出了是历史原因,诸如 printf("%c"...,还有什么其他原因,我翻c标准,没有找到对应内容,可能没看仔细,哪位能给出点其他(非历史)的原因。哈。

加载中
1
mallon
mallon
  • signed char 
    The 8-bit signed char data type can hold integer values in the range of −128 to 127.
  • unsigned char 
    The 8-bit unsigned char data type can hold integer values in the range of 0 to 255.
  • char 
    Depending on your system, the char data type is defined as having the same range as either the signed char or the unsigned char data type (they are three distinct types, however). By convention, you should use the char data type specifically for storing ASCII characters (such as `m'), including escape sequences (such as `\n').
1
mallon
mallon

20.1 Integers

The C language defines several integer data types: integer, short integer, long integer, and character, all in both signed and unsigned varieties. The GNU C compiler extends the language to contain long long integers as well. The C integer types were intended to allow code to be portable among machines with different inherent data sizes (word sizes), so each type may have different ranges on different machines. The problem with this is that a program often needs to be written for a particular range of integers, and sometimes must be written for a particular size of storage, regardless of what machine the program runs on.

To address this problem, the GNU C Library contains C type definitions you can use to declare integers that meet your exact needs. Because the GNU C Library header files are customized to a specific machine, your program source code doesn't have to be.

These typedefs are in stdint.h. If you require that an integer be represented in exactly N bits, use one of the following types, with the obvious mapping to bit size and signedness:

  • int8_t
  • int16_t
  • int32_t
  • int64_t
  • uint8_t
  • uint16_t
  • uint32_t
  • uint64_t

If your C compiler and target machine do not allow integers of a certain size, the corresponding above type does not exist.

If you don't need a specific storage size, but want the smallest data structure with at least N bits, use one of these:

  • int_least8_t
  • int_least16_t
  • int_least32_t
  • int_least64_t
  • uint_least8_t
  • uint_least16_t
  • uint_least32_t
  • uint_least64_t

If you don't need a specific storage size, but want the data structure that allows the fastest access while having at least N bits (and among data structures with the same access speed, the smallest one), use one of these:

  • int_fast8_t
  • int_fast16_t
  • int_fast32_t
  • int_fast64_t
  • uint_fast8_t
  • uint_fast16_t
  • uint_fast32_t
  • uint_fast64_t

If you want an integer with the widest range possible on the platform on which it is being used, use one of the following. If you use these, you should write code that takes into account the variable size and range of the integer.

  • intmax_t
  • uintmax_t

The GNU C Library also provides macros that tell you the maximum and minimum possible values for each integer data type. The macro names follow these examples: INT32_MAX, UINT8_MAX, INT_FAST32_MIN, INT_LEAST64_MIN, UINTMAX_MAX, INTMAX_MAX, INTMAX_MIN. Note that there are no macros for unsigned integer minima. These are always zero. There are similar macros for use with C's built in integer types which should come with your C compiler. These are described in Data Type Measurements.

Don't forget you can use the C sizeof function with any of these data types to get the number of bytes of storage each uses.

1
mallon
mallon

引用来自“中山野鬼”的答案

引用来自“Mallon”的答案

  • signed char 
    The 8-bit signed char data type can hold integer values in the range of −128 to 127.
  • unsigned char 
    The 8-bit unsigned char data type can hold integer values in the range of 0 to 255.
  • char 
    Depending on your system, the char data type is defined as having the same range as either the signed char or the unsigned char data type (they are three distinct types, however). By convention, you should use the char data type specifically for storing ASCII characters (such as `m'), including escape sequences (such as `\n').
你这个是gcc的那篇?
1
mallon
mallon

引用来自“中山野鬼”的答案

引用来自“gvim”的答案

引用来自“中山野鬼”的答案

引用来自“gvim”的答案

引用来自“中山野鬼”的答案

引用来自“gvim”的答案

你可以查一下这个字符集大概只包含96个基本字符+大概10个什么字符构成的执行字符集。这用不着2^8这么多,所以是整数类型的一个子集,表示执行字符集。
0x20 - 0x7e ...可ascii 显示字符应该都包括在里面。但是有个问题,除非是标准或系统库函数,实际代码中,编译器并不会对char类型有什么额外的特定处理。我觉得如果这是历史遗留问题(哪些标准库导致),就真是个“无聊的bug“了。哈。

很多时候不得不处理历史遗留,这就是工程,并不是国际上所有键盘都是现在这个样子,参看vi发明时候的键盘。编译器会不会对char有什么处理,这不是实现域的概念,而是逻辑域的概念,实现域要求要么遵循unsigned char的实现要么遵循signed char的实现,编译器既然有类型系统,那就自然遵循类型系统的签名检查。就如同size_t一样,你实现上可以认为size_t和uint32_t是一个东西,可逻辑上它们表达的东西不一样的,逻辑域已经变了。

主要目的还是隔离,保证c代码内部逻辑跨环境下可以复用。其实不指望完全的存逻辑上的c,这也没意义,没有系统库 ,就没有输入输出。无非是要把这些和环境相关的东西,隔离起来,这样可以保障内部逻辑不调整。一调整就是一批bug。。。

用stdint.h呗,每个标准C环境都会有。自己处理这些问题,实在意义不大额。

这样做有缺陷。不同系统库,都有自己的位宽定义。包括我现在在64位下的动态索引,已经全部放弃指针,采用基地址+偏移量的方式处理。实际诸如树,动态链表,都是采用一个 _u32的类型来作为寻址。无非不支持单一连续存储空间超过4G。

以前32位不存在上述问题。在64位下,指针太占空间了。实际上对于未来的图的内核我甚至会使用_u16来做索引,只支持单个连通图少于65536个顶点的情况。

每个标准c环境确实都有自己的位宽定义类型,但是不同标准c环境的位宽定义名称并不代表严格一致。我与其参考一堆标准,不如老老实实的构造自己的类型定义。而且这个类型定义的.h文件,用个小c程序,在指定的设备和编译器下运行一把,便自动生成了。何必慢慢翻别人的资料。

简单说。同样的一个图引擎,直接替换一个类型定义,就可以完成从65536个顶点,扩充到32位个顶点数。

意义不大,这要看你做什么设计了。我这边的设计,以前吃过亏。更何况现在原型用gcc,以后还是要转到intel 的编译器下折腾。

intel编译器又不是神,也就浮点运算快那么一些。在我看来,10倍以内的都不是显著提升。

0
宏哥
宏哥

这种问题太孔乙己了, 你就用没有警告的, 不要问为什么

就像面对两个凡是, 只要坚持即可

应该研究的问题, 给你个例子:

0
擅长被美女推倒
擅长被美女推倒

你最近挺无聊的,可以出去放松下,也可以找几个高中妹妹研究下深浅问题,周一 一起去搞不

0
小耶果
小耶果
VS2012 开启/W4,Gcc开启/Wall都没有任何警告,是我打开方式不对?
0
中山野鬼
中山野鬼

引用来自“擅长被美女推倒”的答案

你最近挺无聊的,可以出去放松下,也可以找几个高中妹妹研究下深浅问题,周一 一起去搞不

不是无聊。我在做c语言里面的类型位宽重定义,例如用_u8 ,_i8 等等重新处理。这个事情几乎所有的系统库都有,而每个团队基本也有自己的"types.h"。 其他整型好说。

无非落到char 上存在这个偏差。如果只是历史原因,那么好说,其他方面的原因还需要考虑下对策。

char 有两个含义,一个是8位宽,一个就是char。关键在于后者,我目前也只能知道大概。

别说 types.h无聊。它对内部代码逻辑和编译器以及目标机器隔离很有帮助。

0
中山野鬼
中山野鬼

引用来自“宏哥”的答案

这种问题太孔乙己了, 你就用没有警告的, 不要问为什么

就像面对两个凡是, 只要坚持即可

应该研究的问题, 给你个例子:

你不知道我在干什么。我在隔离c语言逻辑代码和外部环境。都是落地的事情。如果哪个c团队没有自己的types.h。他们基本不是在做底层。同样的代码,linux 32 和liux 64 差异也都存在。

例如,把指针转换成整型, 64位下,如果你没有 (_I32)(_U64)p ,就是一堆 warning....有空到处该源码,为什么不集中到types.h上。

你有没有遇到类似问题我不知道。至少我的经历告诉我,即便是标准库函数,也需要隔离。每个编译器对标准库函数的实现都存在一定差异。

你不做隔离,以后内部逻辑代码就改吧。。。哈。

0
中山野鬼
中山野鬼

引用来自“小耶果”的答案

VS2012 开启/W4,Gcc开启/Wall都没有任何警告,是我打开方式不对?
我在linux和mac 下使用gcc都存在这个警告。 而且使用 -fsigned-char 等编译选项仍然存在。。网络上有个英文资料。解释了原因,但不是官方的。所以我在寻找更全面的解释。
返回顶部
顶部