除此之外: sizeof(char) = 1 sizeof(long long) = 8 sizeof(long double) = 12
sizeof(unsigned char) = 1 sizeof(unsigned long long) = 8
sizeof运算符可以确定给定的类型占据的字节数。在C语言中sizeof是一个关键字。其结果是一个无符号的整数,可以用%u说明符输出它。其可以确定某个基本的类型的值所占用的内存空间。例如:sizeof(int)会得到int类型的变量所占的字节数,所得的是一个size_t类型的整数。
注意:我们希望把sizeof运算符应用于一个类型,则该类型名就必须放在括号中,例如:sizeof(long double) 。将sizeof运算符应用于表达式时,括号就是可选的。
32位与64位系统数据类型
不同的平台上对不同的数据类型分配的字节数是不同的,一般的,数据类型的字节数是由编辑器决定的(编译期间决定数据类型长度)。
简单来说,平台就是CPU+OS+Compiler,cpu的位是指一次性可处理的数据量是多少,1字节=8位,32位处理器可以一次性处理4个字节的数据量,依次类推。32位操作系统针对的32位的CPU设计。64位操作系统针对的64位的CPU设计。所以平台是三者的组合,它们的字节长相同时,效率最高。
二、极限值
%u 输出无符号整数值。
%e 输出浮点数的极限值,表示这个数值是指数形式。
%f 说明符表示没有指数的数值,它对于非常大或非常小的数来说相当不方便。
类型 | 下限 | 上限 |
---|---|---|
char %d
unsigned char %u |
CHAR_MIN -128
0 |
CHAR_MAX 127
UCHAR_MAX 255 |
short %d
unsigned short %u |
SHRT_MIN -32768
0 |
SHRT_MAX 32767
USHRT_MAX 65535 |
int %d
unsigned int %u |
INT_MIN -2147483648
0 |
INT_MAX 2147483647
UINT_MAX 4294967295 |
long %ld
unsigned long %lu |
LONG_MIN -2147483648
0 |
LONG_MAX 2147483647
ULONG_MAX 4294967295 |
long long %lld
unsigned long long %llu |
LLONG_MIN -9223372036854775808
0 |
LLONG_MAX 9223372036854775807
ULLONG_MAX 18446744073709551615 |
类型 | 下限 | 上限 |
---|---|---|
float %e | FLT_MIN 1.175e-38 | FLT_MAX 3.402823e+38 |
double %e | DBL_MIN 2.225e-308 | DBL_MAX 1.797693e+308 |
long double %Le | LDBL_MIN 3.362e-4932 | LDBL_MAX 1.189731e+4932 |
#include
#include
#include
int main(void)
{
printf("char stor values from %d to %d\n",CHAR_MIN,CHAR_MAX);
printf("float stor values from %.3e to %e\n",FLT_MIN,FLT_MAX);
printf("long stor values from %ld to %ld\n",LONG_MIN,LONG_MAX);
printf("unsigined long long stor values from 0 to %llu\n",ULLONG_MAX);
printf("double stor values from %.3e to %e \n",DBL_MIN,DBL_MAX);
printf("double stor values from %.3Le to %Le \n",LDBL_MIN,LDBL_MAX);
return 0;
}
一系列的printf()函数调用中,输出
三、类型转换
#include
int main(void)
{
const float Revenue_Per_150 = 4.5f;//每销售150个产品的收入
short JanSold = 23500; //一月份的销售额
short FebSold = 19300;
short MarSold = 21600;
float RevQuarter = 0.0f; //每个季度的总收入
short QuarterSold = JanSold + FebSold + MarSold;//一个季度总销售额
printf("Stock sold in \nJan:%d\nFeb:%d\nMar:%d\n",JanSold,FebSold,MarSold);
printf("Total stock sold in first quarter:%d\n",QuarterSold);
RevQuarter = QuarterSold/150*Revenue_Per_150;
printf("Sales revenue this quarter is:$%.2f\n",RevQuarter);//这个季度的销售收入
return 0;
}
输出的结果如下所示:显然输出的结果是错误的,不应该是得到的负值。
Stock sold in
Jan:23500
Feb:19300
Mar:21600
Total stock sold in first quarter:-1136
Sales revenue this quarter is:$-31.50
错误1:QuarterSold变量声明为short类型,其初始值定义为3个月的销售总额,总和是64400,而对于short类型而言,其最大值是32767。现在问题来了,我们试图在变量中存储对short类型而言过大的数字,计算机不能正确解释QuarterSold的值,所以输出了负数。
解决办法:给QuarterSold变量使用unsigned long类型。来存储非常大的数字,还可以把每月销售量的变量指定为无符号类型。
错误2:RevQuarter = QuarterSold/150*Revenue_Per_150; 由于乘除的优先级相同,先回计算64400/150=429.333 最终会舍弃.333。在下一步计算过程中会有出入。
解决办法:方案1:语句改为RevQuarter = QuarterSold*Revenue_Per_150/150;
方案2:语句改为RevQuarter = QuarterSold/150.0*Revenue_Per_150;
方案3:语句改为RevQuarter = (float)QuarterSold/150*Revenue_Per_150;
//最终正确的格式如下:
#include
int main(void)
{
const float Revenue_Per_150 = 4.5f;//每销售150个产品的收入
unsigned short JanSold = 23500; //一月份的销售额
unsigned short FebSold = 19300;
unsigned short MarSold = 21600;
float RevQuarter = 0.0f; //每个季度的总收入
unsigned long QuarterSold = JanSold + FebSold + MarSold;//一个季度总销售额
printf("Stock sold in \nJan:%u\nFeb:%u\nMar:%u\n",JanSold,FebSold,MarSold);
printf("Total stock sold in first quarter:%d\n",QuarterSold);//-->>Total stock sold in first quarter:64400
RevQuarter =(float) QuarterSold/150*Revenue_Per_150;
printf("Sales revenue this quarter is:$%.2f\n",RevQuarter);//这个季度的销售收入 //-->>Sales revenue this quarter is:$1932.00
return 0;
}
强制类型转换:一种类型显示转化为另一种类型的过程。
把变量从一种类型转换为另一种类型,应该把目标类型放在变量前面的括号中。例如:RevQuarter =(float) QuarterSold/150*Revenue_Per_150;
把表达式从一种类型强制转换为另一种类型。此时,应该把表达式放在括号中。例如:result = (fouble)(a*a + b*b);
隐式类型转换:在二元算数运算中使用不同类型的操作数,编译器就会把其中一个值域较小的操作数类型转化为另一个操作数的类型。 例如:RevQuarter = QuarterSold/150*Revenue_Per_150;计算为64400(int)/150(int),结果是429(int) , 再将429(int转换为float)乘以4.5(float),得到1930.5(float)。因为Int类型的值域小于float类型。
//隐式类型转换的规则
(1)如果一个操作数的类型是long double,就把另一个操作数转换为long double类型。
(2)否则,如果一个操作数的类型是double,就把另一个操作数转换为double类型。
(3)否则,如果一个操作数的类型是float,就把另一个操作数转换为float类型。
(4)否则,如果两个操作数的类型都是带符号的整数或者无符号的整数,就把级别较低的操作数换位另一个操作数类型。无符号整数类型的级别从低到高为:
signed char ,short ,int ,long ,long long
每个无符号的整数类型的级别都与对应的带符号整数类型相同,所以unsigned int类型的级别与int类型的相同。
(5)否则,如果带符号整数类型的操作数级别低于无符号整数类型的级别,就把带符号整数类型的操作数转换为无符号整数类型。
(6)否则,如果带符号的整数类型的值域包含了无符号整数类型所表示的值,就把无符号的整数类型转换为带符号的整数类型。
(7)否则,两个操作数都转换为带符号的整数类型对应的无符号的整数类型。
//赋值语句中的隐式类型转换
例如: long double tital_cost = double cost;
当操作数的类型不同时候,赋值操作总是要把右操作数的结果转换为做操作数的类型。所以上述操作的结果会转化为long double类型。编译器不会发出警告,因为double类型的所有值都可以表示为long double.
//隐式类型转换的规则
(1)如果一个操作数的类型是long double,就把另一个操作数转换为long double类型。
(2)否则,如果一个操作数的类型是double,就把另一个操作数转换为double类型。
(3)否则,如果一个操作数的类型是float,就把另一个操作数转换为float类型。
(4)否则,如果两个操作数的类型都是带符号的整数或者无符号的整数,就把级别较低的操作数换位另一个操作数类型。无符号整数类型的级别从低到高为:
signed char ,short ,int ,long ,long long
每个无符号的整数类型的级别都与对应的带符号整数类型相同,所以unsigned int类型的级别与int类型的相同。
(5)否则,如果带符号整数类型的操作数级别低于无符号整数类型的级别,就把带符号整数类型的操作数转换为无符号整数类型。
(6)否则,如果带符号的整数类型的值域包含了无符号整数类型所表示的值,就把无符号的整数类型转换为带符号的整数类型。
(7)否则,两个操作数都转换为带符号的整数类型对应的无符号的整数类型。
//赋值语句中的隐式类型转换
例如: long double tital_cost = double cost;
当操作数的类型不同时候,赋值操作总是要把右操作数的结果转换为做操作数的类型。所以上述操作的结果会转化为long double类型。编译器不会发出警告,因为double类型的所有值都可以表示为long double.
四、枚举
在编程时候,常常希望存储一组可能值中的一个 。例如:一个变量存储表示当前月份的值。这个值应该只存储12个可能值中的一个,分别对应于1~12月。
4.1 枚举类型的定义
enum Weekday{Monday,Tuesday,Wednesday,Thursday,Friday,Saturday,Sunday};
enum Weekday today = Thursday;
只要希望变量有限定数量的可能值,就可以使用枚举。
第一个语句定义了枚举类型Weekday,这个类型的变量可以有括号中的7个值得任意一个。
第二个语句定义了Weekday类型的一个变量,把它初始化为Thursday,其对应的值是3。
1>格式为: enum 枚举的标记 {枚举器/枚举常量};,知Weekday是一个标识符,可有可无;
2>枚举常量的名称必须是唯一的;枚举器有默认值,编译器会把int类型的整数值赋予给每个名称;名称间用逗号,隔开;其数量是可以任意的;枚举器的值不要求是唯一的,除非有特殊原因让某些枚举器的值相同,否则应确保这些值也是唯一的;
3>枚举是一个整数类型, 每个枚举常量对应不同的整数值;
4>第一个枚举成员的默认值为整型的0,后续枚举成员的值在前一个成员上加1。
5> 可以人为设定枚举成员的值,从而自定义某个范围内的整数。
6> 枚举型是预处理指令#define的替代。
7> 类型定义以分号;结束。
4.2 使用枚举类型对变量进行声明
新的数据类型定义完成后,它就可以使用了。我们已经见过最基本的数据类型,如:整型int, 单精度浮点型float, 双精度浮点型double, 字符型char, 短整型short等等。用这些基本数据类型声明变量通常是这样:
char a; //变量a的类型均为字符型char
char letter;
int x,
y,
z; //变量x,y和z的类型均为整型int
int number;
double m, n;
double result; //变量result的类型为双精度浮点型double
既然枚举也是一种数据类型,那么它和基本数据类型一样也可以对变量进行声明。
方法一:枚举类型的定义和变量的声明分开
enum DAY
{
MON=1, TUE, WED, THU, FRI, SAT, SUN
};
enum DAY yesterday;
enum DAY today;
enum DAY tomorrow; //变量tomorrow的类型为枚举型enum DAY
enum DAY good_day, bad_day; //变量good_day和bad_day的类型均为枚举型enum DAY
方法二:类型定义与变量声明同时进行:
//未命名的枚举类型,
//在创建枚举类型的变量时,可以不指定标记,这样就没有枚举类型了。其可能的枚举器从saturday到friday
//该语句还生命了未命名类型的变量workday;可以用通常的方式给其赋值。
//局限性:只要限制是,必须在定义该类型的语句中声明它的所有变量。由于没有类型名,无法在代码的后面定义该类型的其他的变量
enum //跟第一个定义不同的是,此处的标号DAY省略,这是允许的。
{
saturday,
sunday = 0,
monday,
tuesday,
wednesday,
thursday,
friday
} workday; //变量workday的类型为枚举型enum DAY
workday = monnday;
enum week { Mon=1, Tue, Wed, Thu, Fri Sat, Sun} days; //变量days的类型为枚举型enum week
enum BOOLEAN { false, true } end_flag, match_flag; //定义枚举类型并声明了两个枚举型变量
方法三:用typedef关键字将枚举类型定义成别名,并利用该别名进行变量声明:
typedef enum workday
{
saturday,
sunday = 0,
monday,
tuesday,
wednesday,
thursday,
friday
} workday; //此处的workday为枚举型enum workday的别名
workday today, tomorrow; //变量today和tomorrow的类型为枚举型workday,也即enum workday
enum workday中的workday可以省略:
typedef enum
{
saturday,
sunday = 0,
monday,
tuesday,
wednesday,
thursday,
friday
} workday; //此处的workday为枚举型enum workday的别名
workday today, tomorrow; //变量today和tomorrow的类型为枚举型workday,也即enum workday
也可以用这种方式:
typedef enum workday
{
saturday,
sunday = 0,
monday,
tuesday,
wednesday,
thursday,
friday
};
workday today, tomorrow; //变量today和tomorrow的类型为枚举型workday,也即enum workday
注意:同一个程序中不能定义同名的枚举类型,不同的枚举类型中也不能存在同名的命名常量。错误示例如下所示:
错误声明一:存在同名的枚举类型
typedef enum
{
wednesday,
thursday,
friday
} workday;
typedef enum WEEK
{
saturday,
sunday = 0,
monday,
} workday;
错误声明二:存在同名的枚举成员
typedef enum
{
wednesday,
thursday,
friday
} workday_1;
typedef enum WEEK
{
wednesday,
sunday = 0,
monday,
} workday_2;
4.3 使用枚举类型的变量
4.3.1 对枚举型的变量赋值。
实例将枚举类型的赋值与基本数据类型的赋值进行了对比:
方法一:先声明变量,再对变量赋值
#include
/* 定义枚举类型 */
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };
void main()
{
/* 使用基本数据类型声明变量,然后对变量赋值 */
int x, y, z;
x = 10;
y = 20;
z = 30;
/* 使用枚举类型声明变量,再对枚举型变量赋值 */
enum DAY yesterday, today, tomorrow;
yesterday = MON;
today = TUE;
tomorrow = WED;
printf("%d %d %d \n", yesterday, today, tomorrow);
}
方法二:声明变量的同时赋初值
#include
/* 定义枚举类型 */
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };
void main()
{
/* 使用基本数据类型声明变量同时对变量赋初值 */
int x=10, y=20, z=30;
/* 使用枚举类型声明变量同时对枚举型变量赋初值 */
enum DAY yesterday = MON,
today = TUE,
tomorrow = WED;
printf("%d %d %d \n", yesterday, today, tomorrow);
}
方法三:定义类型的同时声明变量,然后对变量赋值。
#include
/* 定义枚举类型,同时声明该类型的三个变量,它们都为全局变量 */
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN } yesterday, today, tomorrow;
/* 定义三个具有基本数据类型的变量,它们都为全局变量 */
int x, y, z;
void main()
{
/* 对基本数据类型的变量赋值 */
x = 10; y = 20; z = 30;
/* 对枚举型的变量赋值 */
yesterday = MON;
today = TUE;
tomorrow = WED;
printf("%d %d %d \n", x, y, z); //输出:10 20 30
printf("%d %d %d \n", yesterday, today, tomorrow); //输出:1 2 3
}
方法四:类型定义,变量声明,赋初值同时进行。
#include
/* 定义枚举类型,同时声明该类型的三个变量,并赋初值。它们都为全局变量 */
enum DAY
{
MON=1,
TUE,
WED,
THU,
FRI,
SAT,
SUN
}
yesterday = MON, today = TUE, tomorrow = WED;
/* 定义三个具有基本数据类型的变量,并赋初值。它们都为全局变量 */
int x = 10, y = 20, z = 30;
void main()
{
printf("%d %d %d \n", x, y, z); //输出:10 20 30
printf("%d %d %d \n", yesterday, today, tomorrow); //输出:1 2 3
}
4.3.2 对枚举型的变量赋整数值时,需要进行类型转换。
#include
enum DAY { MON=1, TUE, WED, THU, FRI, SAT, SUN };
void main()
{
enum DAY yesterday, today, tomorrow;
yesterday = TUE;
today = (enum DAY) (yesterday + 1); //类型转换
tomorrow = (enum DAY) 30; //类型转换
//tomorrow = 3; //错误
printf("%d %d %d \n", yesterday, today, tomorrow); //输出:2 3 30
}
4.3.3 使用枚举型变量
#include
enum
{
BELL = '\a',
BACKSPACE = '\b',
HTAB = '\t',
RETURN = '\r',
NEWLINE = '\n',
VTAB = '\v',
SPACE = ' '
};
enum BOOLEAN { FALSE = 0, TRUE } match_flag;
void main()
{
int index = 0;
int count_of_letter = 0;
int count_of_space = 0;
char str[] = "I'm Ely efod";
match_flag = FALSE;
for(; str[index] != '\0'; index++)
if( SPACE != str[index] )
count_of_letter++;
else
{
match_flag = (enum BOOLEAN) 1;
count_of_space++;
}
printf("%s %d times %c", match_flag ? "match" : "not match", count_of_space, NEWLINE);
printf("count of letters: %d %c%c", count_of_letter, NEWLINE, RETURN);
}
输出:
match 2 times
count of letters: 10
Press any key to continue
4.4 枚举类型与sizeof运算符
复制代码
#include
enum escapes
{
BELL = '\a',
BACKSPACE = '\b',
HTAB = '\t',
RETURN = '\r',
NEWLINE = '\n',
VTAB = '\v',
SPACE = ' '
};
enum BOOLEAN { FALSE = 0, TRUE } match_flag;
void main()
{
printf("%d bytes \n", sizeof(enum escapes)); //4 bytes
printf("%d bytes \n", sizeof(escapes)); //4 bytes
printf("%d bytes \n", sizeof(enum BOOLEAN)); //4 bytes
printf("%d bytes \n", sizeof(BOOLEAN)); //4 bytes
printf("%d bytes \n", sizeof(match_flag)); //4 bytes
printf("%d bytes \n", sizeof(SPACE)); //4 bytes
printf("%d bytes \n", sizeof(NEWLINE)); //4 bytes
printf("%d bytes \n", sizeof(FALSE)); //4 bytes
printf("%d bytes \n", sizeof(0)); //4 bytes
}
4.5 选择枚举值
可以给任意或所有的枚举器指定自己的整数值。尽管枚举器使用的名称必须是唯一的,但是枚举器的值不要求是唯一的。除非有特殊的原因让某些枚举器的值相同,否则一般应确保这些值也是唯一的。
例如:
4.6 综合举例
#include
enum Season
{
spring, summer=100, fall=96, winter
};
typedef enum
{
Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday
}
Weekday;
void main()
{
/* Season */
printf("%d \n", spring); // 0
printf("%d, %c \n", summer, summer); // 100, d
printf("%d \n", fall+winter); // 193
enum Season mySeason=winter;
if(winter==mySeason)
printf("mySeason is winter \n"); // mySeason is winter
int x=100;
if(x==summer)
printf("x is equal to summer\n"); // x is equal to summer
printf("%d bytes\n", sizeof(spring)); // 4 bytes
/* Weekday */
printf("sizeof Weekday is: %d \n", sizeof(Weekday)); //sizeof Weekday is: 4
Weekday today = Saturday;
Weekday tomorrow;
if(today == Monday)
tomorrow = Tuesday;
else
tomorrow = (Weekday) (today + 1); //remember to convert from int to Weekday
printf("today == %d tomorrow == %d\n",today,tomorrow); // today == 5 tomorrow == 6
}
参考链接:
enum与typedef enum的用法:https://blog.csdn.net/king16304/article/details/52193562