ANSI C (5) —— 结构、联合、位字段、枚举

2024-03-27 22:32

本文主要是介绍ANSI C (5) —— 结构、联合、位字段、枚举,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

结构

结构体在声明的时候并没有分配任何的内存资源,只有定义了结构体变量才会产生相应的内存分配。

typedef和#define的区别

#define仅仅是做简单的替换,而typedef是给某种数据类型创建一个替代名。
看这样的例子:

#include <stdio.h>
#define charP char*
int main(){charP s1="I love you.", s2="hello";return 0;
}

编译:

$ gcc typedef.c 
typedef.c: In function ‘main’:
typedef.c:4:29: warning: initialization makes integer from pointer without a castcharP s1="I love you.", s2="hello";^

typedef:

#include <stdio.h>
typedef char* charP;
int main(){charP s1="I love you.", s2="hello";return 0;
}

编译:

$ gcc typedef.c

结构体直接赋值

#include <stdio.h>
typedef struct node{char *s;int a;float b;
}Node;
int main(){Node A;A.s = "hello";A.a = 12;A.b = 2.5;Node B = A;printf("s is %s, a is %d, b is %f\n",B.s,B.a,B.b);return 0;
}
#include <stdio.h>
#include <string.h>
typedef struct node{char s[30];int a;float b;
}Node;
int main(){Node A;strcpy(A.s,"hello");A.a = 12;A.b = 2.5;Node B = A;printf("s is %s, a is %d, b is %f\n",B.s,B.a,B.b);return 0;
}
/*
edemon@ubuntu1:~/workspace$ ./a.out 
s is hello, a is 12, b is 2.500000
*/

结构体的嵌套

结构体定义中含有另一种结构体,这是合法的:

struct point{int x,y;
};
struct trangle{struct point p[3]; 
};

但是含有自身类型就是非法的了。

struct trangle{struct trangle p[3]; 
};
/*
$ gcc struct1.c 
struct1.c:8:17: error: array type has incomplete element typestruct trangle p[3]; ^
*/

结构体定义中可以拥有指向自身类型结构的指针。这样的自指结构是合法的。

struct trangle{struct trangle* p[3]; 
};

自指结构最典型的应用就是链表。

结构体定义的注意点

和C++不同,C不能在结构体中定义函数,因为C约定结构和算法(函数)是分开的。
看下面的代码:

struct man{char *name;void show(){printf("hello, I'm %s.\n",name);}
};
int main(void) {struct man man1;man1.name = "wei";man1.show();return EXIT_SUCCESS;
}

直接编译,我们会得到这样的信息: error: ‘struct man’ has no member named ‘show’
而如果是在C++ 中编译,这不会有问题。
C++ 中的struct是有this指针的,如下代码可以正常运行:

struct man{char *name;man(const char *name){strcpy(this->name,name);}void show(){printf("hello, I'm %s.\n",name);}
};

结构体中的成员默认都是public的。
结构体不能包含显式的无参构造函数。如:

struct man{char *name;man(const char *name){//strcpy(this->name,name);this->name = (char *)name;}man(){this->name = "??";}void show(){printf("hello, I'm %s.\n",name);}
};
int main(void) {struct man man2();man2.show();return EXIT_SUCCESS;
}

我们将得到:

error: request for member ‘show’ in ‘man2’, which is of non-class typeman()’

将man()删除仍然有这样的错误,这是为什么,因为结构体是没有默认的构造函数的,涉及到initobj等指令。

结构从基类OBJECT继承,但它不支持继承。

联合

联合体的存储

联合变量的存储区域可以存储多类型的数据。但是在任何时候,它只能存储一种数据,联合变量的大小是size最大成员的大小。
下面是一个联合的例子,涉及到C++的typeid操作符,用于判断数据类型。

#include <typeinfo>
#include <iostream>
#include <stdio.h>
using namespace std;union numbers{char letter;int number;float dec_number;double pre_number;
};
int main(){union numbers num;num.letter = 'a';printf("typeid return %s, out data type size is %d, union numbers size is %d\n",\typeid(num.letter).name(),sizeof(num.letter),sizeof(num));num.number = 1;printf("typeid return %s, out data type size is %d, union numbers size is %d\n",\typeid(num.number).name(),sizeof(num.number),sizeof(num));num.dec_number = 1.0f;printf("typeid return %s, out data type size is %d, union numbers size is %d\n",\typeid(num.dec_number).name(),sizeof(num.dec_number),sizeof(num));num.pre_number = 1.0;printf("typeid return %s, out data type size is %d, union numbers size is %d\n",\typeid(num.pre_number).name(),sizeof(num.pre_number),sizeof(num));return 0;
}

执行:

# ./a.out 
typeid return c, out data type size is 1, union numbers size is 8
typeid return i, out data type size is 4, union numbers size is 8
typeid return f, out data type size is 4, union numbers size is 8
typeid return d, out data type size is 8, union numbers size is 8

联合的嵌套

在联合的定义中可以存在另一种不同的联合类型。比如:

union numbers{char letter;int number;float dec_number;double pre_number;
};
union Union{union numbers num;
};

和结构体是一样的,它不能自身嵌套定义,比如:

union Union{union Union num;
};

我们也能定义含有指向自身类型的指针的联合类型。

union Union{union Union* num;
};

在这种情况下,num的类型已经改变,不再是自身。

位字段

首先复习一下字节、位等关键概念。Byte为字节,bit即位。转换
1B = 8b; 1KB = 1024B; 1MB = 1024KB; 1GB = 1024MB.
使用位字段,结构的成员被压缩到了一起,允许程序员在位的层次上访问内存,节省存储空间。注:位字段的数据类型必须是(signed) int、unsigned int。同时,位字段类型变量

不能地址操作 //--> error: cannot take address of bit-field ‘field1’   
不能计算字节数,sizeof   //error: ‘sizeof’ applied to a bit-field  

看看这个例子:

#include <stdio.h>
#include <stdlib.h>
struct temp{int field1:8;int field2:16;long long t;};
int main(){struct temp num;//printf("struct temp size is %d, field1 size is %d, field2 size is %d\n",sizeof(struct temp),sizeof(num.field1),sizeof(num.field2));//void *p = (void *)&num.field1;printf("struct temp size is %d\n",sizeof(struct temp));return 0;
}

编译执行

[root@CentOS workspace]# gcc bit.c 
[root@CentOS workspace]# ./a.out 
struct temp size is 12

field1和field2的内存占用是3个字节,int数据类型的字节数是4,所以最终结构体的内存占用是4+8 = 12.

枚举

通过枚举,我们可以定义自己的几种可能值的数据类型。
在默认的情况下,第一个值和0关联,第二个值和1关联…
C语言中没有布尔数据类型,我们可以自定义。
比如:

#include <stdio.h>
#include <stdlib.h>
enum Boolean {false,true};
typedef enum Boolean bool;
bool check(int tag){if(tag&1) return false;return true;
}
int main(){if(check(2)) puts("even");else puts("odd");   return 0;
}

如果是自定义枚举成员的值,那么未自定义的成员按照顺序增大的原则赋值。比如:

#include <stdio.h>
#include <stdlib.h>
enum Node{t1=1, t2, t3=5, t4, t5};
int main(){printf("t2 is %d, t4 is %d, t5 is %d\n",t2,t4,t5);return 0;
}
/*
[root@CentOS workspace]# ./a.out 
t2 is 2, t4 is 6, t5 is 7
*/

值得注意的是,enum的变量可以被任意赋值(不过只能给枚举变量赋值整数哈),不一定是定义的枚举成员。

#include <stdio.h>
#include <stdlib.h>
enum Node{t1=1, t2, t3=5, t4, t5};
int main(){//printf("t2 is %d, t4 is %d, t5 is %d\n",t2,t4,t5);enum Node t=-1;printf("t is %d\n",t);  return 0;
}

这篇关于ANSI C (5) —— 结构、联合、位字段、枚举的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/853602

相关文章

Vite 打包目录结构自定义配置小结

《Vite打包目录结构自定义配置小结》在Vite工程开发中,默认打包后的dist目录资源常集中在asset目录下,不利于资源管理,本文基于Rollup配置原理,本文就来介绍一下通过Vite配置自定义... 目录一、实现原理二、具体配置步骤1. 基础配置文件2. 配置说明(1)js 资源分离(2)非 JS 资

Kotlin 枚举类使用举例

《Kotlin枚举类使用举例》枚举类(EnumClasses)是Kotlin中用于定义固定集合值的特殊类,它表示一组命名的常量,每个枚举常量都是该类的单例实例,接下来通过本文给大家介绍Kotl... 目录一、编程枚举类核心概念二、基础语法与特性1. 基本定义2. 带参数的枚举3. 实现接口4. 内置属性三、

Java集合中的链表与结构详解

《Java集合中的链表与结构详解》链表是一种物理存储结构上非连续的存储结构,数据元素的逻辑顺序的通过链表中的引用链接次序实现,文章对比ArrayList与LinkedList的结构差异,详细讲解了链表... 目录一、链表概念与结构二、当向单链表的实现2.1 准备工作2.2 初始化链表2.3 打印数据、链表长

创建springBoot模块没有目录结构的解决方案

《创建springBoot模块没有目录结构的解决方案》2023版IntelliJIDEA创建模块时可能出现目录结构识别错误,导致文件显示异常,解决方法为选择模块后点击确认,重新校准项目结构设置,确保源... 目录创建spChina编程ringBoot模块没有目录结构解决方案总结创建springBoot模块没有目录

C#之枚举类型与随机数详解

《C#之枚举类型与随机数详解》文章讲解了枚举类型的定义与使用方法,包括在main外部声明枚举,用于表示游戏状态和周几状态,枚举值默认从0开始递增,也可手动设置初始值以生成随机数... 目录枚举类型1.定义枚举类型(main外)2.使用生成随机数总结枚举类型1.定义枚举类型(main外)enum 类型名字

SpringBoot利用树形结构优化查询速度

《SpringBoot利用树形结构优化查询速度》这篇文章主要为大家详细介绍了SpringBoot利用树形结构优化查询速度,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录一个真实的性能灾难传统方案为什么这么慢N+1查询灾难性能测试数据对比核心解决方案:一次查询 + O(n)算法解决

C语言自定义类型之联合和枚举解读

《C语言自定义类型之联合和枚举解读》联合体共享内存,大小由最大成员决定,遵循对齐规则;枚举类型列举可能值,提升可读性和类型安全性,两者在C语言中用于优化内存和程序效率... 目录一、联合体1.1 联合体类型的声明1.2 联合体的特点1.2.1 特点11.2.2 特点21.2.3 特点31.3 联合体的大小1

Oracle查询表结构建表语句索引等方式

《Oracle查询表结构建表语句索引等方式》使用USER_TAB_COLUMNS查询表结构可避免系统隐藏字段(如LISTUSER的CLOB与VARCHAR2同名字段),这些字段可能为dbms_lob.... 目录oracle查询表结构建表语句索引1.用“USER_TAB_COLUMNS”查询表结构2.用“a

从入门到精通MySQL联合查询

《从入门到精通MySQL联合查询》:本文主要介绍从入门到精通MySQL联合查询,本文通过实例代码给大家介绍的非常详细,需要的朋友可以参考下... 目录摘要1. 多表联合查询时mysql内部原理2. 内连接3. 外连接4. 自连接5. 子查询6. 合并查询7. 插入查询结果摘要前面我们学习了数据库设计时要满

MySQL数据库的内嵌函数和联合查询实例代码

《MySQL数据库的内嵌函数和联合查询实例代码》联合查询是一种将多个查询结果组合在一起的方法,通常使用UNION、UNIONALL、INTERSECT和EXCEPT关键字,下面:本文主要介绍MyS... 目录一.数据库的内嵌函数1.1聚合函数COUNT([DISTINCT] expr)SUM([DISTIN