默认数据类型是整数数据类型
- 计算时整数是最小的数据类型,即使对更小的数据类型进行相加时, 这些数据类型首先会扩展到整数数据类型
初始化变量
用以下方法可以初始化变量:
- int zahl = 100;
- int zahl(100); // c++
在定义全局变量或局部静态变量时必须用常量或字面量赋值。
- int zahl = 100 + 10 * 3 //正确
- int zahl = strlen(str1) // 报错
全局变量或局部静态变量在没有赋初始值是会自动赋值为0
局部变量没有被初始化时,其内容取决于先前对堆栈上分配的内存位置的使用情况。
整数数据类型
数据类型 | 所占比特(64位系统) |
---|---|
char | 8 |
short/ short int | 16 |
int | 32 |
long/ long int | 32/64 |
long long int | 64 |
浮点数
数据类型 | 所占字节 |
---|---|
float | 4 |
double | 8 |
long double | 10 |
数据的比较与计算
数据比较或计算时两个数据必须是相同的数据类型,否则将作以下处理:
- 隐式转化
- 显式转化
类型的隐式转化
一般来说:隐式转化规则的设置方式是,一个数据类型总是被转换为另一个具有 "更大 "数值范围的数据类型,这样就可以尽可能地减少数据损失。
规则如下:
-
浮点数第一
- 如果一个操作数是长双的类型,那么另一个操作数将被转换为长双。
- 如果一个操作数是双数类型,那么另一个操作数将被转换为双数。
- 否则,如果一个操作数是float类型,那么另一个操作数将被转换为float。
-
如果不涉及浮点类型,适用一下规则。无符号数的权重比有符号数高。
-
如果一个操作数是无符号长类型,那么另一个操作数将被转换为无符号长。
(注意:如果要转换的数据类型是有符号的long类型,可能会有数据丢失。) -
if一个操作数是long类型,另一个是无符号int类型,那么如果long可以表示无符号int的所有值(64位到32位),无符号int操作数被转换为long;否则,两个操作数被转换为无符号long(32位到32位)。
-
else if一个操作数是长类型,那么另一个操作数将被转换为长。
-
else if 一个操作数是无符号int类型,那么另一个操作数将被转换为无符号int。
-
-
对于指针、指向数组的指针、指向函数的指针,没有隐含的规则
Struct Types
语法:struct [Strukturname] {Datentyp Variablenname; …} [Variablenliste];
定义结构体的不同方式:
- 只带结构体名字的定义:
struct xyz {int x; int y,z;};
struct xyz var1;
var1.x=7;
//使用结构体定义实例时前面必须带上struct.
struct xyz {int x,y,z;};
// 实例的名字可以与结构体的名字相同。
struct xyz xyz;
xyz var2; //KO
- 只带变量列表的定义:
也被称为匿名定义,用这种方式定义的结构体只能够使用结构体后定义好的变量,后面不能够再自己定义该结构体的实例
struct {int x,y,z;} xyz,arr[3],*ptr=&xyz;
xyz.x=1; arr[1].y=2; ptr->x=7;
- 即有结构体名字又有变量列表:
用户既可以使用已经定义好的变量,也可以在后续自己再定义实例
结构体元素的使用
- 对于变量:‘.’
- 对于指针:’->’
struct xyz {int x,y,z;};
struct abc {
int a,b,c;
struct xyz xyz;
struct {char str[10];} strstr;
struct xyz *ptr;
}var1;
var1.a var1.b var1.c
var1.xyz.x
var1.strstr.str[0]
var1.ptr = &var1.xyz; var1.ptr->x;
初始化结构体
初始化元素通过{}书写。在括号内既可以按顺序初始化值也可以使用’.'操作符
struct dummy{int a,b,c; char str[10];};
struct dummy var1 = {1,2,3,"hallo"};
struct dummy var2 = { .b=3;}; // Rest wird mit 0 initialisiert //gibt’s nicht bei C++!
struct dummy var1 = {.a=strlen(var1.str);}; //var1.a = 0
结构体的内部原理
编译器为结构体保留相应数据结构大小的储存空间
struct {int x,y,z;} var1; //Speicherplatz = 4+4+4 = 12 Byte
sizeof(var1) //12
变量名称对应于结构中第一个元素的指针(对应于一个数组)。因此,结构体内部的元素应被视为基址的偏移运算符。 因此,变量var1中的元素y通过变量的地址(例如地址0x100)加上元素y的偏移量(这里是4,因为第一个结构元素占用了0…3的偏移量)来寻址。
offsetof操作符
语法:offsetof(a,b)-> 给出结构体成员b在结构体a中的偏移量
该操作符在stddef.h头文件中
struct xyz {int a,b,c;} var1;
offsetof(var1,c) //报错,第一个参数应当是结构体的名字而不是实例
offsetof(struct xyz,c) //8
结构体的比较
通过比较别的变量的方式来比较结构体是错误的
struct xyz {int x,y,h} var1,var2;
if(var1 == var2) //报错
结构体的比较应当是这样:
if(var1.x == var2.x && var1.y == var2.y …)
if(memcmp(&var1,&var2,sizeof(var1) == 0)
int memcmp (const void *s1, const void *s2, size_t n)
- memcmp()用来比较s1 和s2 所指的内存区间前n 个字符。
- 字符串大小的比较是以ASCII 码表上的顺序来决定,次顺序亦为字符的值。memcmp()首先将s1 第一个字符值减去s2 第一个字符的值,若差为0 则再继续比较下个字符,若差值不为0 则将差值返回。例如,字符串"Ac"和"ba"比较则会返回字符’A’(65)和’b’(98)的差值(-33)。
- 返回值:若参数s1 和s2 所指的内存内容都完全相同则返回0 值。s1 若大于s2 则返回大于0 的值。s1 若小于s2 则返回小于0 的值。
结构体显示转化
不可以将一个普通的变量显示转化为结构体
typedef
用于生成一种数据类型的别名
语法:typedef datentyp alias[,alias][,*alias];
typedef unsigned int uint32_t;
typedef unsigned int UINT1,UINT2,*PINT;
UINT1 var1;
PINT1 ptr1;
struct test {int a,b,c;};
typedef struct test test_t1;
typedef struct {int a,b,c;} test_t2; //Anonyme Deklaration von Struct ist ausreichend
typedef struct xyz {struct xyz *next; …} test_t3;
typedef enum {STATUS_OK, STATUS_KO} STATUS;
STATUS func() {return STATUS_OK; return 0; return drei;}
union
union中,所有的组件并不像struct那样从连续的内存地址开始,而是从相同的内存地址开始,也就是说,它们的内存区域完全或至少部分地重叠。因此,union只能包含一个元素。一个联盟所占的内存与它最大的组成部分一样多
语法:Syntax: union 共用体名 {
成员列表
} [Variablenliste];
定义union的不同方式
- 只带联合体名字的定义:
union data{
int n;
char ch;
double f;
};
union data a, b, c;
- 只带变量列表的定义:
也被称为匿名定义,用这种方式定义的联合体只能够使用结构体后定义好的变量,后面不能够再自己定义该联合体的实例
union{
int n;
char ch;
double f;
} a, b, c;
- 即有结构体名字又有变量列表:
用户既可以使用已经定义好的变量,也可以在后续自己再定义实例
union data{
int n;
char ch;
double f;
} a, b, c;
应用
#include <stdio.h>
union data{
int n;
char ch;
short m;
};
int main(){
union data a;
printf("%d, %d\n", sizeof(a), sizeof(union data) );
a.n = 0x40;
printf("%X, %c, %hX\n", a.n, a.ch, a.m);
a.ch = '9';
printf("%X, %c, %hX\n", a.n, a.ch, a.m);
a.m = 0x2059;
printf("%X, %c, %hX\n", a.n, a.ch, a.m);
a.n = 0x3E25AD54;
printf("%X, %c, %hX\n", a.n, a.ch, a.m);
return 0;
}
运行结果:
4, 4
40, @, 40
39, 9, 39
2059, Y, 2059
3E25AD54, T, AD54
enum
语法:enum [enumation-name] {definition-list[=expression]} [Variablenliste] ;
不同的定义方式
前三种方式与struct与union类似,但是enum类型的匿名定义方式也是有意义的
enum {HALLO,WELT};
int var1=HALLO,var2=WELT;
// var1 = 0, var2 = 1
在定义是使用计算也是可以的
{bill=10, john=bill+2, fred=john+1}