[转]从两道经典试题谈C/C++中联合体(union)的使用

宋宝华 21cnbao [email protected]

试题一:编写一段程序判断系统中的CPU是Little endian还是Big endian模式?

分析:

作为一个计算机相关专业的人,我们应该在计算机组成中都学习过什么叫Little endian和Big endian。Little endian和Big endian是CPU存放数据的两种不同顺序。对于整型、长整型等数据类型,Big endian认为第一个字节是最高位字节(按照从低地址到高地址的顺序存放数据的高位字节到低位字节);而Little endian则相反,它认为第一个字节是最低位字节(按照从低地址到高地址的顺序存放数据的低位字节到高位字节)。

例如,假设从内存地址0x0000开始有以下数据:


0x0000

0x0001

0x0002

0x0003

0x12

0x34

0xab

0xcd

如果我们去读取一个地址为0x0000的四个字节变量,若字节序为big-endian,则读出结果为0x1234abcd;若字节序位little-endian,则读出结果为0xcdab3412。如果我们将0x1234abcd写入到以0x0000开始的内存中,则Little endian和Big endian模式的存放结果如下:


地址

0x0000

0x0001

0x0002

0x0003

big-endian

0x12

0x34

0xab

0xcd

little-endian

0xcd

0xab

0x34

0x12

一般来说,x86系列CPU都是little-endian的字节序,PowerPC通常是Big endian,还有的CPU能通过跳线来设置CPU工作于Little endian还是Big endian模式。

解答:

显然,解答这个问题的方法只能是将一个字节(CHAR/BYTE类型)的数据和一个整型数据存放于同样的内存开始地址,通过读取整型数据,分析CHAR/BYTE数据在整型数据的高位还是低位来判断CPU工作于Little endian还是Big endian模式。得出如下的答案:

typedef unsigned char BYTE;

int main(int argc, char* argv[])

{

unsigned int num,*p;

p = #

num = 0;

*(BYTE *)p = 0xff;

if(num == 0xff)

{

printf("The endian of cpu is little\n");

}

else    //num == 0xff000000

{

printf("The endian of cpu is big\n");

}

return 0;

}

除了上述方法(通过指针类型强制转换并对整型数据首字节赋值,判断该赋值赋给了高位还是低位)外,还有没有更好的办法呢?我们知道,union的成员本身就被存放在相同的内存空间(共享内存,正是union发挥作用、做贡献的去处),因此,我们可以将一个CHAR/BYTE数据和一个整型数据同时作为一个union的成员,得出如下答案:

int checkCPU()

{

 {

  union w

  {

   int a;

   char b;

  } c;

  c.a = 1;

  return (c.b == 1);

 }

}

实现同样的功能,我们来看看Linux操作系统中相关的源代码是怎么做的:

static union { char c[4]; unsigned long l; } endian_test = { { ‘l‘, ‘?‘, ‘?‘, ‘b‘ } };

#define ENDIANNESS ((char)endian_test.l)

Linux的内核作者们仅仅用一个union变量和一个简单的宏定义就实现了一大段代码同样的功能!由以上一段代码我们可以深刻领会到Linux源代码的精妙之处!

试题二:假设网络节点A和网络节点B中的通信协议涉及四类报文,报文格式为“报文类型字段+报文内容的结构体”,四个报文内容的结构体类型分别为STRUCTTYPE1~ STRUCTTYPE4,请编写程序以最简单的方式组织一个统一的报文数据结构。

分析:

报文的格式为“报文类型+报文内容的结构体”,在真实的通信中,每次只能发四类报文中的一种,我们可以将四类报文的结构体组织为一个union(共享一段内存,但每次有效的只是一种),然后和报文类型字段统一组织成一个报文数据结构。

解答:

根据上述分析,我们很自然地得出如下答案:

typedef unsigned char BYTE;

//报文内容联合体

typedef union tagPacketContent

{

STRUCTTYPE1 pkt1;

STRUCTTYPE2 pkt2;

STRUCTTYPE3 pkt1;

STRUCTTYPE4 pkt2;

}PacketContent;

//统一的报文数据结构

typedef struct tagPacket

{

BYTE pktType;

PacketContent pktContent;

}Packet;

总结

在C/C++程序的编写中,当多个基本数据类型或复合数据结构要占用同一片内存时,我们要使用联合体(试题一是这样的例证);当多种类型,多个对象,多个事物只取其一时(我们姑且通俗地称其为“n选1”),我们也可以使用联合体来发挥其长处(试题二是这样的例证)。

本文出自 “宋宝华的博客” 博客,请务必保留此出处http://21cnbao.blog.51cto.com/109393/120108

时间: 2024-10-13 06:36:49

[转]从两道经典试题谈C/C++中联合体(union)的使用的相关文章

两道笔试题的感触

今天做了两道笔试题,收益良多.有些题,你会发现,虽然并不难,但是却很容易没有思路或者出错,这都是源自平时的不求甚解.很多知识点,自以为已经掌握,其实只是管中窥豹,可见一斑.不要一味墨守成规,也要用于思考,很多东西既要知其然,也要知其所以然.我一直觉得了解和精通中间差着十万八千里,看来还有很长一段路要走.只有比别人更早.更勤奋地努力,才能尝到更加成功的滋味.哈哈,跑题了. 下面看一下两道笔试题.一.大概简单地说一下,求下面这段代码的结果. new Thread(new Runnable() { p

设计的两道面试题C++

1.函数指针的,说明下面程序会出现编译错误吗?如果有怎么解决: class A { private : typedef void (*FUNC)(void); Func a; public : void funcA() {} void funcB() { a = funcA(); a(); } } void main() { A a; a.funcB(); } 2.map应用,下列函数的执行结果 #include <map> #include <iostream> static c

用两道面试题带你详细了解 Java 类加载机制

在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Grandpa{static{System.out.println("爷爷在静态代码块");}} class Father extends Grandpa{static{System.out.println("爸爸在静态代码块");}public static int factor = 25;public Father(){System.out.println("

两道面试题,带你透彻解析Java类加载机制

在许多Java面试中,我们经常会看到关于Java类加载机制的考察,例如下面这道题: class Grandpa { static { System.out.println("爷爷在静态代码块"); } } class Father extends Grandpa { static { System.out.println("爸爸在静态代码块"); } public static int factor = 25; public Father() { System.ou

两道经典算法题-吉比特2017秋招笔试

阅读目录 求素数 最大差值 回到顶部 求素数 输入M.N,1 < M < N < 1000000,求区间[M,N]内的所有素数的个数.素数定义:除了1以外,只能被1和自己整除的自然数称为素数 输入描述: 两个整数M,N 输出描述: 区间内素数的个数 示例1 输入 2 10 输出 4 #include<iostream> #define K 1000001 using namespace std; char p[K+1] = {1,1,0}; //数组前三个数 0 1 2 分别

两道笔试题

"char a='\72'"是什么意思? 这么理解:\为转义字符,\072转义为一个八进制数072,也就是十进制数的58 买一送一,将转义字符对照表也一并贴给你吧:转义字符 意义 ASCII码值(十进制) \a 响铃(BEL) 007 \b 退格(BS) 008 \f 换页(FF) 012 \n 换行(LF) 010 \r 回车(CR) 013 \t 水平制表(HT) 009 \v 垂直制表(VT) 011 \\ 反斜杠 092 \? 问号字符 063 \' 单引号字符 039 \&q

ctrip的两道笔试题

第一个问题可以抽象为这样:给定一个数组A,和一个数t,用数组里的一些数求和得到t,数组里的数可以重复使用,写一个算法,使得使用A中最少的数来表示t. 比如:[2,4,6,9],18==>[9,9] dfs问题 //numbers要从大到小,一个sort搞定,result存放结果 bool dfs(vector<int>& numbers,int gap,int start,vector<int> &result) { if(0 == gap) { return

关于Spring的几道经典试题

1. Spring的Ioc和aop分别是用什么原理实现的? 主要应用了java的反射技术 2.spring 的工作机制以及为什么要用? 1) spring mvc请所有的请求都提交给DispatcherServlet,它会委托应用系统的其他模块负责负责对请求进行真正的处理工作. 2) DispatcherServlet查询一个或多个HandlerMapping,找到处理请求的Controller. 3) DispatcherServlet请请求提交到目标Controller 4) Control

C++两道笔试题

//现给定一个含有n个元素的数组,请随机获取其中的m个元素(不能重复获取). #include <iostream> #include <stdlib.h> using namespace std; void Grial(int a[], int n,int x) { int *b = new int[x]; int k = 0; int i = n; while (x--) { int j = rand() % i; b[k++] = a[j]; a[j] = a[i - 1];