深入理解C语言-----各数据类型大小
2017-10-23 11:10
399 查看
首先看下C标准中“未明确定义”的三种类型Implementation-defined、Unspecified和Undefined。
Implementation-defined 的情况,是C 标准没有明确规定,但是要求编译器必须对此做出明确规定,并写在编译器的文档中。
Unspecified的情况,往往有几种可选的处理方式,C 标准没有明确规定按哪种方式处理,编译器可以自己决定,并且也不必写在编译器的文档中,这样即使用同一个编译器的不同版本来编译也可能得到不同的结果,因为编译器没有在文档中明确写它会怎么处理,那么不同版本的编译器就可以选择不同的处理方式,比如一个函数调用的各个实参表达式按什么顺序求值是Unspecified的。
Undefined的情况则是完全不确定的,C 标准没规定怎么处理,编译器很可能也没规定,甚至也没做出错处理,有很多Undefined的情况是编译器是检查不出来的,最终会导致运行时错误,比如数组访问越界就是Undefined的。
除了char型在C 标准中明确规定占一个字节之外,其它整数类型占几个字节都是Implementation Defined。通常的编译器实现遵守ILP32 或LP64规范。
LP32 这个缩写的意思是int (I )、long(L )和指针(P )类型都占32位,通常32位计算机的C 编译器采用这种规范,x86 平台的gcc 也是如此。LP64是指long(L )和指针占64位,通常64位计算机的C 编译器采用这种规范。指针类型的长度总是和计算机的位数一致。
(PS下,long long 类型对应的占位符和平台和编译器有关,linux中gcc很统一用%lld,在windows中,MinGW的gcc和VC6都需要用到%I64d,但VS2008却是%lld)
在limit.h文件中有比较详细的定义
[cpp]
view plain
copy
print?
/* Copyright (C) 1991, 1992, 1996, 1997, 1998, 1999, 2000, 2005
Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/*
*<span style="white-space: pre;"> </span>ISO C99 Standard: 7.10/5.2.4.2.1 Sizes of integer types<span style="white-space: pre;"> </span><limits.h>
*/
[cpp]
view plain
copy
print?
*/
#ifndef _LIBC_LIMITS_H_
#define _LIBC_LIMITS_H_ 1
#include <features.h>
/* Maximum length of any multibyte character in any locale.
We define this value here since the gcc header does not define
the correct value. */
#define MB_LEN_MAX 16
/* If we are not using GNU CC we have to define all the symbols ourself.
Otherwise use gcc's definitions (see below). */
#if !defined __GNUC__ || __GNUC__ < 2
/* We only protect from multiple inclusion here, because all the other
#include's protect themselves, and in GCC 2 we may #include_next through
multiple copies of this file before we get to GCC's. */
# ifndef _LIMITS_H
# define _LIMITS_H 1
#include <bits/wordsize.h>
/* We don't have #include_next.
Define ANSI <limits.h> for standard 32-bit words. */
/* These assume 8-bit `char's, 16-bit `short int's,
and 32-bit `int's and `long int's. */
/* Number of bits in a `char'
dab9
. */
# define CHAR_BIT 8
/* Minimum and maximum values a `signed char' can hold. */
# define SCHAR_MIN (-128)
# define SCHAR_MAX 127
/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
# define UCHAR_MAX 255
/* Minimum and maximum values a `char' can hold. */
# ifdef __CHAR_UNSIGNED__
# define CHAR_MIN 0
# define CHAR_MAX UCHAR_MAX
# else
# define CHAR_MIN SCHAR_MIN
# define CHAR_MAX SCHAR_MAX
# endif
/* Minimum and maximum values a `signed short int' can hold. */
# define SHRT_MIN (-32768)
# define SHRT_MAX 32767
/* Maximum value an `unsigned short int' can hold. (Minimum is 0.) */
# define USHRT_MAX 65535
/* Minimum and maximum values a `signed int' can hold. */
# define INT_MIN (-INT_MAX - 1)
# define INT_MAX 2147483647
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
# define UINT_MAX 4294967295U
/* Minimum and maximum values a `signed long int' can hold. */
# if __WORDSIZE == 64
# define LONG_MAX 9223372036854775807L
# else
# define LONG_MAX 2147483647L
# endif
# define LONG_MIN (-LONG_MAX - 1L)
/* Maximum value an `unsigned long int' can hold. (Minimum is 0.) */
# if __WORDSIZE == 64
# define ULONG_MAX 18446744073709551615UL
# else
# define ULONG_MAX 4294967295UL
# endif
# ifdef __USE_ISOC99
/* Minimum and maximum values a `signed long long int' can hold. */
# define LLONG_MAX 9223372036854775807LL
# define LLONG_MIN (-LLONG_MAX - 1LL)
/* Maximum value an `unsigned long long int' can hold. (Minimum is 0.) */
# define ULLONG_MAX 18446744073709551615ULL
# endif /* ISO C99 */
# endif /* limits.h */
#endif /* GCC 2. */
#endif /* !_LIBC_LIMITS_H_ */
/* Get the compiler's limits.h, which defines almost all the ISO constants.
We put this #include_next outside the double inclusion check because
it should be possible to include this file more than once and still get
the definitions from gcc's header. */
#if defined __GNUC__ && !defined _GCC_LIMITS_H_
/* `_GCC_LIMITS_H_' is what GCC's file defines. */
# include_next <limits.h>
#endif
/* The <limits.h> files in some gcc versions don't define LLONG_MIN,
LLONG_MAX, and ULLONG_MAX. Instead only the values gcc defined for
ages are available. */
#if defined __USE_ISOC99 && defined __GNUC__
# ifndef LLONG_MIN
# define LLONG_MIN (-LLONG_MAX-1)
# endif
# ifndef LLONG_MAX
# define LLONG_MAX __LONG_LONG_MAX__
# endif
# ifndef ULLONG_MAX
# define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
# endif
#endif
#ifdef __USE_POSIX
/* POSIX adds things to <limits.h>. */
# include <bits/posix1_lim.h>
#endif
#ifdef __USE_POSIX2
# include <bits/posix2_lim.h>
#endif
#ifdef __USE_XOPEN
# include <bits/xopen_lim.h>
#endif
注意一点:对于不带signed 或unsigned 关键字的char型,C 标准规定这是Implementation Defined ,编译器可以定义char型是无符号的,也可以定义char型是有符号的,在该编译器所对应的体系结构上哪种实现效率高就可以采用哪种实现,x86 平台的gcc 定义char是有符号的。这也是C 标准的Rationale之一:优先考虑效率,而可移植性尚在其次。另外,除了char型以外的整数类型(short,int,long,long long)如果不明确写signed 或unsigned
关键字都表示有符号数,这一点是C 标准明确规定的。
有符号数在计算机中的表示形式是Sign and Magnitude 、1's Complement还是2's Complement?C 标准也没有明确规定,也是Implementation Defined 。大多数体系结构都采用2's Complement表示形式和加减运算规则,x86 平台也是如此。
注意,ASCII码的取值范围是0~127 ,所以不管char型是有符号的还是无符号的,存一个ASCII码都没有问题,一般来说,如果用char型存ASCII码字符,就不必明确写signed 还是unsigned ,如果把char型当作8 位的整数来用,为了可移植性就必须写明是signed 还是unsigned 。
如果不是为了效率,一般来说就没有理由故意写不可移植的代码。比如Linux内核代码使用了很多gcc 特性以得到最佳的执行效率,在写的时候就没打算用别的编译器编译,也就没考虑可移植性的问题。可见C 语言与平台和编译器是密不可分的,离开了具体的平台和编译器讨论C 语言必然难以深入
C 标准规定的浮点型有float、double 、long double ,和整数类型一样,既没有规定每种类型占多少字节,也没有规定采用哪种表示形式。浮点数的实现在各种平台上差异很大,x86 处理器通常是有浮点运算单元的,遵循IEEE 754,float型通常是32位,double 型通常是64位。要详细了解浮点数的IEEE表示可以查看CSAPP的第二章2.4.2 .具体的定义可以查看float.h
首先看下C标准中“未明确定义”的三种类型Implementation-defined、Unspecified和Undefined。
Implementation-defined 的情况,是C 标准没有明确规定,但是要求编译器必须对此做出明确规定,并写在编译器的文档中。
Unspecified的情况,往往有几种可选的处理方式,C 标准没有明确规定按哪种方式处理,编译器可以自己决定,并且也不必写在编译器的文档中,这样即使用同一个编译器的不同版本来编译也可能得到不同的结果,因为编译器没有在文档中明确写它会怎么处理,那么不同版本的编译器就可以选择不同的处理方式,比如一个函数调用的各个实参表达式按什么顺序求值是Unspecified的。
Undefined的情况则是完全不确定的,C 标准没规定怎么处理,编译器很可能也没规定,甚至也没做出错处理,有很多Undefined的情况是编译器是检查不出来的,最终会导致运行时错误,比如数组访问越界就是Undefined的。
除了char型在C 标准中明确规定占一个字节之外,其它整数类型占几个字节都是Implementation Defined。通常的编译器实现遵守ILP32 或LP64规范。
LP32 这个缩写的意思是int (I )、long(L )和指针(P )类型都占32位,通常32位计算机的C 编译器采用这种规范,x86 平台的gcc 也是如此。LP64是指long(L )和指针占64位,通常64位计算机的C 编译器采用这种规范。指针类型的长度总是和计算机的位数一致。
(PS下,long long 类型对应的占位符和平台和编译器有关,linux中gcc很统一用%lld,在windows中,MinGW的gcc和VC6都需要用到%I64d,但VS2008却是%lld)
在limit.h文件中有比较详细的定义
[cpp]
view plain
copy
print?
/* Copyright (C) 1991, 1992, 1996, 1997, 1998, 1999, 2000, 2005
Free Software Foundation, Inc.
This file is part of the GNU C Library.
The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with the GNU C Library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
/*
*<span style="white-space: pre;"> </span>ISO C99 Standard: 7.10/5.2.4.2.1 Sizes of integer types<span style="white-space: pre;"> </span><limits.h>
*/
/* Copyright (C) 1991, 1992, 1996, 1997, 1998, 1999, 2000, 2005 Free Software Foundation, Inc. This file is part of the GNU C Library. The GNU C Library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The GNU C Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with the GNU C Library; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */ /* * ISO C99 Standard: 7.10/5.2.4.2.1 Sizes of integer types <limits.h> */
[cpp]
view plain
copy
print?
*/
#ifndef _LIBC_LIMITS_H_
#define _LIBC_LIMITS_H_ 1
#include <features.h>
/* Maximum length of any multibyte character in any locale.
We define this value here since the gcc header does not define
the correct value. */
#define MB_LEN_MAX 16
/* If we are not using GNU CC we have to define all the symbols ourself.
Otherwise use gcc's definitions (see below). */
#if !defined __GNUC__ || __GNUC__ < 2
/* We only protect from multiple inclusion here, because all the other
#include's protect themselves, and in GCC 2 we may #include_next through
multiple copies of this file before we get to GCC's. */
# ifndef _LIMITS_H
# define _LIMITS_H 1
#include <bits/wordsize.h>
/* We don't have #include_next.
Define ANSI <limits.h> for standard 32-bit words. */
/* These assume 8-bit `char's, 16-bit `short int's,
and 32-bit `int's and `long int's. */
/* Number of bits in a `char'
dab9
. */
# define CHAR_BIT 8
/* Minimum and maximum values a `signed char' can hold. */
# define SCHAR_MIN (-128)
# define SCHAR_MAX 127
/* Maximum value an `unsigned char' can hold. (Minimum is 0.) */
# define UCHAR_MAX 255
/* Minimum and maximum values a `char' can hold. */
# ifdef __CHAR_UNSIGNED__
# define CHAR_MIN 0
# define CHAR_MAX UCHAR_MAX
# else
# define CHAR_MIN SCHAR_MIN
# define CHAR_MAX SCHAR_MAX
# endif
/* Minimum and maximum values a `signed short int' can hold. */
# define SHRT_MIN (-32768)
# define SHRT_MAX 32767
/* Maximum value an `unsigned short int' can hold. (Minimum is 0.) */
# define USHRT_MAX 65535
/* Minimum and maximum values a `signed int' can hold. */
# define INT_MIN (-INT_MAX - 1)
# define INT_MAX 2147483647
/* Maximum value an `unsigned int' can hold. (Minimum is 0.) */
# define UINT_MAX 4294967295U
/* Minimum and maximum values a `signed long int' can hold. */
# if __WORDSIZE == 64
# define LONG_MAX 9223372036854775807L
# else
# define LONG_MAX 2147483647L
# endif
# define LONG_MIN (-LONG_MAX - 1L)
/* Maximum value an `unsigned long int' can hold. (Minimum is 0.) */
# if __WORDSIZE == 64
# define ULONG_MAX 18446744073709551615UL
# else
# define ULONG_MAX 4294967295UL
# endif
# ifdef __USE_ISOC99
/* Minimum and maximum values a `signed long long int' can hold. */
# define LLONG_MAX 9223372036854775807LL
# define LLONG_MIN (-LLONG_MAX - 1LL)
/* Maximum value an `unsigned long long int' can hold. (Minimum is 0.) */
# define ULLONG_MAX 18446744073709551615ULL
# endif /* ISO C99 */
# endif /* limits.h */
#endif /* GCC 2. */
#endif /* !_LIBC_LIMITS_H_ */
/* Get the compiler's limits.h, which defines almost all the ISO constants.
We put this #include_next outside the double inclusion check because
it should be possible to include this file more than once and still get
the definitions from gcc's header. */
#if defined __GNUC__ && !defined _GCC_LIMITS_H_
/* `_GCC_LIMITS_H_' is what GCC's file defines. */
# include_next <limits.h>
#endif
/* The <limits.h> files in some gcc versions don't define LLONG_MIN,
LLONG_MAX, and ULLONG_MAX. Instead only the values gcc defined for
ages are available. */
#if defined __USE_ISOC99 && defined __GNUC__
# ifndef LLONG_MIN
# define LLONG_MIN (-LLONG_MAX-1)
# endif
# ifndef LLONG_MAX
# define LLONG_MAX __LONG_LONG_MAX__
# endif
# ifndef ULLONG_MAX
# define ULLONG_MAX (LLONG_MAX * 2ULL + 1)
# endif
#endif
#ifdef __USE_POSIX
/* POSIX adds things to <limits.h>. */
# include <bits/posix1_lim.h>
#endif
#ifdef __USE_POSIX2
# include <bits/posix2_lim.h>
#endif
#ifdef __USE_XOPEN
# include <bits/xopen_lim.h>
#endif
*/ #ifndef _LIBC_LIMITS_H_ #define _LIBC_LIMITS_H_ 1 #include <features.h> /* Maximum length of any multibyte character in any locale. We define this value here since the gcc header does not define the correct value. */ #define MB_LEN_MAX 16 /* If we are not using GNU CC we have to define all the symbols ourself. Otherwise use gcc's definitions (see below). */ #if !defined __GNUC__ || __GNUC__ < 2 /* We only protect from multiple inclusion here, because all the other #include's protect themselves, and in GCC 2 we may #include_next through multiple copies of this file before we get to GCC's. */ # ifndef _LIMITS_H # define _LIMITS_H 1 #include <bits/wordsize.h> /* We don't have #include_next. Define ANSI <limits.h> for standard 32-bit words. */ /* These assume 8-bit `char's, 16-bit `short int's, and 32-bit `int's and `long int's. */ /* Number of bits in a `char'. */ # define CHAR_BIT 8 /* Minimum and maximum values a `signed char' can hold. */ # define SCHAR_MIN (-128) # define SCHAR_MAX 127 /* Maximum value an `unsigned char' can hold. (Minimum is 0.) */ # define UCHAR_MAX 255 /* Minimum and maximum values a `char' can hold. */ # ifdef __CHAR_UNSIGNED__ # define CHAR_MIN 0 # define CHAR_MAX UCHAR_MAX # else # define CHAR_MIN SCHAR_MIN # define CHAR_MAX SCHAR_MAX # endif /* Minimum and maximum values a `signed short int' can hold. */ # define SHRT_MIN (-32768) # define SHRT_MAX 32767 /* Maximum value an `unsigned short int' can hold. (Minimum is 0.) */ # define USHRT_MAX 65535 /* Minimum and maximum values a `signed int' can hold. */ # define INT_MIN (-INT_MAX - 1) # define INT_MAX 2147483647 /* Maximum value an `unsigned int' can hold. (Minimum is 0.) */ # define UINT_MAX 4294967295U /* Minimum and maximum values a `signed long int' can hold. */ # if __WORDSIZE == 64 # define LONG_MAX 9223372036854775807L # else # define LONG_MAX 2147483647L # endif # define LONG_MIN (-LONG_MAX - 1L) /* Maximum value an `unsigned long int' can hold. (Minimum is 0.) */ # if __WORDSIZE == 64 # define ULONG_MAX 18446744073709551615UL # else # define ULONG_MAX 4294967295UL # endif # ifdef __USE_ISOC99 /* Minimum and maximum values a `signed long long int' can hold. */ # define LLONG_MAX 9223372036854775807LL # define LLONG_MIN (-LLONG_MAX - 1LL) /* Maximum value an `unsigned long long int' can hold. (Minimum is 0.) */ # define ULLONG_MAX 18446744073709551615ULL # endif /* ISO C99 */ # endif /* limits.h */ #endif /* GCC 2. */ #endif /* !_LIBC_LIMITS_H_ */ /* Get the compiler's limits.h, which defines almost all the ISO constants. We put this #include_next outside the double inclusion check because it should be possible to include this file more than once and still get the definitions from gcc's header. */ #if defined __GNUC__ && !defined _GCC_LIMITS_H_ /* `_GCC_LIMITS_H_' is what GCC's file defines. */ # include_next <limits.h> #endif /* The <limits.h> files in some gcc versions don't define LLONG_MIN, LLONG_MAX, and ULLONG_MAX. Instead only the values gcc defined for ages are available. */ #if defined __USE_ISOC99 && defined __GNUC__ # ifndef LLONG_MIN # define LLONG_MIN (-LLONG_MAX-1) # endif # ifndef LLONG_MAX # define LLONG_MAX __LONG_LONG_MAX__ # endif # ifndef ULLONG_MAX # define ULLONG_MAX (LLONG_MAX * 2ULL + 1) # endif #endif #ifdef __USE_POSIX /* POSIX adds things to <limits.h>. */ # include <bits/posix1_lim.h> #endif #ifdef __USE_POSIX2 # include <bits/posix2_lim.h> #endif #ifdef __USE_XOPEN # include <bits/xopen_lim.h> #endif
注意一点:对于不带signed 或unsigned 关键字的char型,C 标准规定这是Implementation Defined ,编译器可以定义char型是无符号的,也可以定义char型是有符号的,在该编译器所对应的体系结构上哪种实现效率高就可以采用哪种实现,x86 平台的gcc 定义char是有符号的。这也是C 标准的Rationale之一:优先考虑效率,而可移植性尚在其次。另外,除了char型以外的整数类型(short,int,long,long long)如果不明确写signed 或unsigned
关键字都表示有符号数,这一点是C 标准明确规定的。
有符号数在计算机中的表示形式是Sign and Magnitude 、1's Complement还是2's Complement?C 标准也没有明确规定,也是Implementation Defined 。大多数体系结构都采用2's Complement表示形式和加减运算规则,x86 平台也是如此。
注意,ASCII码的取值范围是0~127 ,所以不管char型是有符号的还是无符号的,存一个ASCII码都没有问题,一般来说,如果用char型存ASCII码字符,就不必明确写signed 还是unsigned ,如果把char型当作8 位的整数来用,为了可移植性就必须写明是signed 还是unsigned 。
如果不是为了效率,一般来说就没有理由故意写不可移植的代码。比如Linux内核代码使用了很多gcc 特性以得到最佳的执行效率,在写的时候就没打算用别的编译器编译,也就没考虑可移植性的问题。可见C 语言与平台和编译器是密不可分的,离开了具体的平台和编译器讨论C 语言必然难以深入
C 标准规定的浮点型有float、double 、long double ,和整数类型一样,既没有规定每种类型占多少字节,也没有规定采用哪种表示形式。浮点数的实现在各种平台上差异很大,x86 处理器通常是有浮点运算单元的,遵循IEEE 754,float型通常是32位,double 型通常是64位。要详细了解浮点数的IEEE表示可以查看CSAPP的第二章2.4.2 .具体的定义可以查看float.h
相关文章推荐
- 深入理解C语言-----各数据类型大小
- 深入理解计算机各种类型大小(sizeof)
- 深入理解数据类型、变量属性、内存四区和指针
- 深入理解js generator数据类型
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的结构和类型--HashTable
- C语言常用数据类型的大小
- 深入理解C++浮点数(float、double)类型数据比较、相等判断
- 深入理解sizeof+C语言数据类型+内存补齐
- 深入理解Java之数据类型
- 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的作用域
- C语言数据类型在单片机 MCU 中占的内存大小
- C语言基本数据类型的大小
- C语言:基本数据类型,限定符,大小范围
- C语言中各种数据类型的大小
- 深入理解C++浮点数(float、double)类型数据比较、相等判断
- 深入理解C++浮点数(float、double)类型数据比较、相等判断
- C语言里的数据类型的大小及占用字节
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--简略
- [李景山php] 深入理解PHP内核[读书笔记]--第三章:变量及数据类型--变量的结构和类型--常量
- Microsoft visual C++ 2010学习版中C语言基本数据类型所占字节大小(系统为64位win8.1)