前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >文件I/O (二).结构体存取(2)

文件I/O (二).结构体存取(2)

作者头像
franket
发布2021-09-16 09:48:53
5560
发布2021-09-16 09:48:53
举报
文章被收录于专栏:技术杂记技术杂记

编译执行过程中没有报错,从结果来看,f1、f2文件中的内容变化也符合预期


小技巧

宏定义

在写代码的过程偶尔会用到一些宏,这些宏多定义在头文件中,通过查看头文件,就可以获取相关信息

如我们想知道 O_RDWR 的定义

代码语言:javascript
复制
emacs@ubuntu:~$ grep O_RDWR  /usr/include/* -r
/usr/include/asm-generic/fcntl.h:#define O_RDWR		00000002
/usr/include/bits/fcntl.h:#define O_RDWR		     02
/usr/include/linux/fs.h: * to O_WRONLY and O_RDWR via the strange trick in __dentry_open()
/usr/include/linux/smbno.h:#define SMB_O_RDWR	0x0002
emacs@ubuntu:~$

我们想知道 SEEK_SET、SEEK_CUR、SEEK_END 的宏定义

代码语言:javascript
复制
emacs@ubuntu:~$ grep SEEK_SET  /usr/include/* 
/usr/include/fcntl.h:# define SEEK_SET	0	/* Seek from beginning of file.  */
/usr/include/libio.h:   beginning of the file (if W is SEEK_SET),
/usr/include/stdio.h:#define SEEK_SET	0	/* Seek from beginning of file.  */
/usr/include/unistd.h:# define SEEK_SET	0	/* Seek from beginning of file.  */
/usr/include/unistd.h:# define L_SET		SEEK_SET
/usr/include/unistd.h:   beginning of the file (if WHENCE is SEEK_SET),
emacs@ubuntu:~$ grep SEEK_CUR  /usr/include/* 
/usr/include/fcntl.h:# define SEEK_CUR	1	/* Seek from current position.  */
/usr/include/libio.h:   the current position (if W is SEEK_CUR),
/usr/include/stdio.h:#define SEEK_CUR	1	/* Seek from current position.  */
/usr/include/unistd.h:# define SEEK_CUR	1	/* Seek from current position.  */
/usr/include/unistd.h:# define L_INCR		SEEK_CUR
/usr/include/unistd.h:   the current position (if WHENCE is SEEK_CUR),
emacs@ubuntu:~$ grep SEEK_END  /usr/include/* 
/usr/include/fcntl.h:# define SEEK_END	2	/* Seek from end of file.  */
/usr/include/libio.h:   or the end of the file (if W is SEEK_END).
/usr/include/stdio.h:#define SEEK_END	2	/* Seek from end of file.  */
/usr/include/unistd.h:# define SEEK_END	2	/* Seek from end of file.  */
/usr/include/unistd.h:# define L_XTND		SEEK_END
/usr/include/unistd.h:   or the end of the file (if WHENCE is SEEK_END).
emacs@ubuntu:~$ 

我们还可以使用这种方式来查看函数原型

如我们想知道 lseek 函数的原型

代码语言:javascript
复制
emacs@ubuntu:~$ grep lseek  /usr/include/* 
/usr/include/_G_config.h:#define _G_LSEEK64	__lseek64
/usr/include/unistd.h:/* Values for the WHENCE argument to lseek.  */
/usr/include/unistd.h:extern __off_t lseek (int __fd, __off_t __offset, int __whence) __THROW;
/usr/include/unistd.h:extern __off64_t __REDIRECT_NTH (lseek,
/usr/include/unistd.h:				 lseek64);
/usr/include/unistd.h:#  define lseek lseek64
/usr/include/unistd.h:extern __off64_t lseek64 (int __fd, __off64_t __offset, int __whence)
emacs@ubuntu:~$

Tip: 如果我们事先知道一个函数来自于哪一个头文件,就可以进一步地缩小范围,有时一个函数的头文件里并没有直接包含,可能是这个头文件所include的文件中包含,多时可能达到4到5层


内存对齐

在定义有结构体的代码中,要留意内存对齐的问题

哪什么是内存对齐呢,我们可以看看下面的一个例子:

代码语言:javascript
复制
#include <stdio.h>

int main()
{
  struct st1
  {
    char a;
    int b;
    char c;
  };

  struct st2
  {
    char a;
    char c;
    int b;
  };
  
  printf("size of st1:%d\nsize of st2:%d\n",sizeof(struct st1),sizeof(struct st2));
  return 0;
}

我们将它编译运行

代码语言:javascript
复制
emacs@ubuntu:~/c$ alias gtc
alias gtc='gcc -Wall -g -o'
emacs@ubuntu:~/c$ gtc duiqi.x duiqi.c 
emacs@ubuntu:~/c$ ./duiqi.x 
size of st1:12
size of st2:8
emacs@ubuntu:~/c$ 

从结果来看,包含同样内容的两个结构体,占用的内存却是不一样的,而区别只在于它们内部元素的排列方式不一样

1-4-1 的顺序占用了12个字节,1-1-4 的顺序占用了8个字节

这就是内存对齐的效果

在C语言中,结构是一种复合数据类型,其构成元素既可以是基本数据类型(如int、long、float等)的变量,也可以是一些复合数据类型(如数组、结构、联合等)的数据单元。在结构中,编译器为结构的每个成员按其自然边界(alignment)分配空间。各个成员按照它们被声明的顺序在内存中顺序存储,第一个成员的地址和整个结构的地址相同。

为了使CPU能够对变量进行快速的访问,变量的起始地址应该具有某些特性,即所谓的”对齐”.比如4字节的int型,其起始地址应该位于4字节的边界上,即起始地址能够被4整除

字节对齐的作用不仅是便于cpu快速访问,同时合理的利用字节对齐可以有效地节省存储空间。

对于32位机来说,4字节对齐能够使cpu访问速度提高,比如说一个long类型的变量,如果跨越了4字节边界存储,那么cpu要读取两次,这样效率就低了。但是在32位机中使用1字节或者2字节对齐,反而会使变量访问速度降低。所以这要考虑处理器类型,另外还得考虑编译器的类型。在vc中默认是4字节对齐的,GNU gcc 也是默认4字节对齐


xxd

xxd是一个很好用的命令,可以用来查看二进制文件

代码语言:javascript
复制
emacs@ubuntu:~/c$ xxd f1
0000000: 0b00 0000 7869 616f 0000 0000 1200 0000  ....xiao........
0000010: 0d00 0000 686f 6e67 0000 0000 5800 0000  ....hong....X...
0000020: 1000 0000 7475 6e61 0000 0000 6200 0000  ....tuna....b...
0000030: 1300 0000 746f 6e79 0000 0000 3c00 0000  ....tony....<...
0000040: 5a00 0000 6475 6e6f 0000 0000 6200 0000  Z...duno....b...
emacs@ubuntu:~/c$ xxd f2
0000000: 1000 0000 7475 6e61 0000 0000 6200 0000  ....tuna....b...
0000010: 5a00 0000 6475 6e6f 0000 0000 6200 0000  Z...duno....b...
emacs@ubuntu:~/c$ 

本文系转载,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文系转载前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 小技巧
    • 宏定义
    • 内存对齐
    • xxd
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档