十二、结构体

结构体

1、定义结构体

Go 语言中数组可以存储同一类型的数据,但在结构体中我们可以为不同项定义不同的数据类型。
结构体是由一系列具有相同类型或不同类型的数据构成的数据集合。
结构体定义需要使用 type 和 struct 语句。struct 语句定义一个新的数据类型,结构体中有一个或多个成员。type 语句设定了结构体的名称。
代码示例

package main
 
import "fmt"
 
//定义结构体
type Books struct {
    title string
    author string
    subject string
    bookId int
}
 
func main() {
    // 创建一个新的结构体
    fmt.Println(Books{"Go 语言", "mr.white", "Go语言教程", 100001})

    // 也可以使用 key => value 格式
    fmt.Println(Books{title: "Go 语言", author: "mr.white", subject: "Go语言教程", bookId: 100002})

    // 忽略的字段为 0 或 空
    fmt.Println(Books{title: "Go 语言", author: "mr.white"})
}

查看运行结果
在这里插入图片描述

2、访问结构体成员

如果要访问结构体成员,需要使用点号 . 操作符。

package main
 
import "fmt"
 
//定义结构体
type Books struct {
    title string
    author string
    subject string
    bookId int
}
 
func main() {
    Book1 := Books
    /* book 1 描述 */
    Book1.title = "Go 语言"
    Book1.author = "mr.white"
    Book1.subject = "Go 语言教程"
    Book1.bookId = 100001

    Book2 := Books
    /* book 2 描述 */
    Book2.title = "Python 教程"
    Book2.author = "mr.white"
    Book2.subject = "Python 语言教程"
    Book2.bookId = 100002

    /* 打印 Book1 信息 */
    fmt.Printf("Book 1 title : %s\n", Book1.title)
    fmt.Printf("Book 1 author : %s\n", Book1.author)
    fmt.Printf("Book 1 subject : %s\n", Book1.subject)
    fmt.Printf("Book 1 book_id : %d\n", Book1.bookId)

    /* 打印 Book2 信息 */
    fmt.Printf("Book 2 title : %s\n", Book2.title)
    fmt.Printf("Book 2 author : %s\n", Book2.author)
    fmt.Printf("Book 2 subject : %s\n", Book2.subject)
    fmt.Printf("Book 2 book_id : %d\n", Book2.bookId)
}

查看运行结果
在这里插入图片描述

3、结构体作为函数

实例代码

package main

import "fmt"

//定义一个类型
type tsh struct {
    //定义成员,类型是func() string
    test func() string
}

func main() {
    t := tsh{
        test: func() string {
            return "123"
        },
    }
    fmt.Println(t.test())
}

查看运行结果
在这里插入图片描述

4、结构体指针

代码示例

package main
 
import "fmt"
 
func main() {
    type Person struct {
        id   int
        name string
    }
 
    var tom = Person{1, "tom"}
 
    var p_person *Person
    p_person = &tom
    fmt.Printf("tom: %v\n", tom)
    fmt.Printf("p_person: %p\n", p_person)
    fmt.Printf("*p_person: %v\n", *p_person)
}

查看运行结果
在这里插入图片描述

### C语言结构体对齐的原理和方法 #### 一、结构体对齐的基本概念 在C语言中,为了提高数据访问效率以及满足硬件架构的要求,编译器会对结构体中的成员进行内存对齐处理。这种对齐遵循一定的规则,主要包括以下几个方面: 1. **第一个成员的位置** 结构体的第一个成员始终存储在其分配空间的起始地址上[^2]。 2. **其他成员的对齐规则** 对于后续成员,它们会被放置在一个特定数值(称为对齐数)的整数倍地址处。这个对齐数通常是该成员类型的大小或者编译器指定的默认对齐值两者之间的最小值。 3. **填充字节的作用** 如果某个成员无法直接放在下一个可用位置而违反上述规则,则会通过插入额外的填充字节来调整其位置,从而实现正确的对齐[^3]。 4. **整体大小调整** 整个结构体最终占据的空间也需是对其中最宽基本类型成员大小的一个整数倍;如果必要的话,在最后一个字段后面还会增加一些尾部填充以达到这一目标。 #### 二、影响因素分析 - **平台差异** - 不同的操作系统可能有不同的默认对齐策略。例如,在Windows环境下使用Microsoft Visual Studio开发工具链时,默认情况下采用的是8字节边界对齐模式;而在大多数Linux发行版里则倾向于更紧凑些即按4字节单位排列。 - **自定义指令控制** - 开发者可以利用预处理器命令`#pragma pack(n)`来自行设定新的打包参数n (通常为1,2,4,...),以此改变当前作用域内的所有新声明对象内部组件间的间隔程度[#1]. #### 三、实例解析 考虑以下代码片段及其运行结果解释: ```c #include<stdio.h> #pragma pack(8)//交代按照8字节对齐宽度 struct A { char x;//占用1字节 char y; char z; }; struct B { char x; int y;//占用4字节 char z; }; int main(){ struct A a; struct B b; printf("%d\n",sizeof(a)); // 输出3 printf("%d\n",sizeof(b)); // 输出12 return 0; } ``` 对于结构A而言,由于三个字符型变量连续分布并无任何中间隔开的需求所以实际消耗正好等于各自长度之和也就是3字节[^1]。 然而针对B来说情况变得复杂起来因为存在不同类型的数据混合在一起的情况: - 首先是单字节的'x',它自然位于偏移量为零的地方; - 接下来的'int y'(四字节),考虑到前面已经用了1个字节因此这里需要补齐至最近合适的四位点再开始计数故产生了三个空闲位使得y真正意义上的起点应该是第四个单元格而非第二个; - 最后的另一个单独存在的char 'z'同样也要顾及之前留下的空白进而再次跳过直至找到适合自己的八分之一界限才正式安顿下来再加上必要的结尾补充总共构成了十二个有效区域^. #### 四、总结说明 综上所述,C编程环境里的复合资料形式——结构体并非简单地把各个组成部分堆叠起来就算完成而是经过精心设计过的布局过程旨在兼顾性能表现的同时又能保持良好的可移植特性.[^2] ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值