联合(union)

联合(union)C/C++里面见得并不多,但是在一些对内存要求特别严格的地方,联合又是频繁出现,那么究竟什么是联合、怎么去用、有什么需要注意的地方呢?就这些问题,我试着做一些简单的回答,里面肯定还有不当的地方,欢迎指出!
1、什么是联合?
  
联合是一种特殊的类,也是一种构造类型的数据结构。在一个联合内可以定义多种不同的数据类型, 一个被说明为该联合类型的变量中,允许装入该联合所定义的任何一种数据,这些数据共享同一段内存,已达到节省空间的目的(还有一个节省空间的类型:位域)。 这是一个非常特殊的地方,也是联合的特征。另外,同struct一样,联合默认访问权限也是公有的,并且,也具有成员函数。

2、联合与结构的区别?
  
联合结构有一些相似之处。但两者有本质上的不同。在结构中各成员有各自的内存空间, 一个结构变量的总长度是各成员长度之和(空结构除外,同时不考虑边界调整)。而在联合中,各成员共享一段内存空间, 一个联合变量的长度等于各成员中最长的长度。应该说明的是, 这里所谓的共享不是指把多个成员同时装入一个联合变量内, 而是指该联合变量可被赋予任一成员值,但每次只能赋一种值, 赋入新值则冲去旧值。

   下面举一个例了来加对深联合的理解。
   
4:

#include <stdio.h>
void main()
{
        union number
        {                   /*
定义一个联合*/
                int i;
                struct
                {             /*
在联合中定义一个结构*/
                        char first;
                        char second;
                }half;
        }num;
        num.i=0x4241;         /*
联合成员赋值*/
        printf("%c%c/n", num.half.first, num.half.second);
        num.half.first='a';   /*
联合中结构成员赋值*/
        num.half.second='b';
        printf("%x/n", num.i);
        getchar();
}
   
输出结果为:
     AB
     6261
   
从上例结果可以看出: 当给i赋值后, 其低八位也就是firstsecond的值; 当给firstsecond赋字符后, 这两个字符的ASCII码也将作为i 的低八位和高八位。

3、如何定义?
  
例如:
    union test
    {
      test() { }
      int office;
      char teacher[5];
    };
   
定义了一个名为test的联合类型,它含有两个成员,一个为整型,成员名office;另一个为字符数组,数组名为teacher。联合定义之后,即可进行联合变量说明,被说明为test类型的变量,可以存放整型量office或存放字符数组teacher

4、如何说明?
  
联合变量的说明有三种形式:先定义再说明、定义同时说明和直接说明。
  
test类型为例,说明如下:
    1) union test
       {
         int office;
         char teacher[5];
       };
       union test a,b;    /*
说明a,btest类型*/
    2) union test
       {
         int office;
         char teacher[5];
       } a,b;
    3) union
       {
         int office;
         char teacher[5];
       } a,b;
      
经说明后的a,b变量均为test类型。a,b变量的长度应等于test的成员中最长的长度,即等于teacher数组的长度,共5个字节。a,b变量如赋予整型值时,只使用了4个字节,而赋予字符数组时,可用5个字节。

5、如何使用?
  
对联合变量的赋值,使用都只能是对变量的成员进行。联合变量的成员表示为:    

联合变量名.成员名
例如,a被说明为test类型的变量之后,可使用a.classa.office

不允许只用联合变量名作赋值或其它操作,也不允许对联合变量作初始化赋值,赋值只能在程序中进行。
还要再强调说明的是,一个联合变量,每次只能赋予一个成员值。换句话说,一个联合变量的值就是联合变员的某一个成员值。

6、匿名联合
  
匿名联合仅仅通知编译器它的成员变量共同享一个地址,而变量本身是直接引用的,不使用通常的点号运算符语法.例如:
    
i nclude <iostream>
     void main()
     {
         union{
                int test;
                char c;
               };         
        test=5;
        c=
a;
        std::cout<<i<<" "<<c;
     }
   
正如所见到的,联合成分象声明的普通局部变量那样被引用,事实上对于程序而言,这也正是使用这些变量的方式.另外,尽管被定义在一个联合声明中,他们与同一个程序快那的任何其他局部变量具有相同的作用域级别.这意味这匿名联合内的成员的名称不能与同一个作用域内的其他一直标志符冲突.
   
对匿名联合还存在如下限制:
   
因为匿名联合不使用点运算符,所以包含在匿名联合内的元素必须是数据,不允许有成员函数,也不能包含私有或受保护的成员。还有,全局匿名联合必须是静态(static)的,否则就必须放在匿名名字空间中。

7、几点需要讨论的地方:
   1
、联合里面那些东西不能存放?
     
我们知道,联合里面的东西共享内存,所以静态、引用都不能用,因为他们不可能共享内存。
   2
、类可以放入联合吗?
     
我们先看一个例子:
      class Test
      {
      public:
    Test():data(0) { }
      private:
          int data;
      };

     typedef union _test
     {
Test test; 
     }UI; 
    
编译通不过,为什么呢?
    
因为联合里不允许存放带有构造函数、析够函数、复制拷贝操作符等的类,因为他们共享内存,编译器无法保证这些对象不被破坏,也无法保证离开时调用析够函数。
    3
、又是匿名惹的祸??
      
我们先看下一段代码:
class test
{
        public:
             test(const char* p);
             test(int in);
             const operator char*() const {return

data.ch;}
             operator long() const {return data.l;}
        private:
     enum type {Int, String };
            union
     {
const char* ch;
int i;
      }datatype;
      type stype;
      test(test&);
      test& operator=(const test&);
        };
       test::test(const char *p):stype

(String),datatype.ch(p)     { }
       test::test(int in):stype(Int),datatype.l(i)     {

}
    
看出什么问题了吗?呵呵,编译通不过。为什么呢?难道datatype.ch(p)datatype.l(i)有问题吗?
    
哈哈,问题在哪呢?让我们来看看构造test对象时发生了什么,当创建test对象时,自然要调用其相应的构造函数,在构造函数中当然要调用其成员的构造函数,所以其要去调用datatype成员的构造函数,但是他没有构造函数可调用,所以出

错。
    
注意了,这里可并不是匿名联合!因为它后面紧跟了个data!
    4
、如何有效的防止访问出错?
      
使用联合可以节省内存空间,但是也有一定的风险:通过一个不适当的数据成员获取当前对象的值!例如上面的chi交错访问。
      
为了防止这样的错误,我们必须定义一个额外的对象,来跟踪当前被存储在联合中的值得类型,我们称这个额外的对象为:union的判别式。
      
一个比较好的经验是,在处理作为类成员的union对象时,为所有union数据类型提供一组访问函数。

 

 

 

 

 

在数据库中,UNIONUNION ALL关键字都是将两个结果集合并为一个,但这两者从使用和效率上来说都有所不同。

UNION在进行表链接后会筛选掉重复的记录,所以在表链接后会对所产生的结果集进行排序运算,删除重复的记录再返回结果。

实际大部分应用中是不会产生重复的记录,最常见的是过程表与历史表UNION。如:

select * from gc_dfys

union

select * from ls_jg_dfys

这个SQL在运行时先取出两个表的结果,再用排序空间进行排序删除重复的记录,最后返回结果集,如果表数据量大的话可能会导致用磁盘进行排序。

UNION ALL只是简单的将两个结果合并后就返回。这样,如果返回的两个结果集中有重复的数据,那么返回的结果集就会包含重复的数据了。

从效率上说,UNION ALL要比UNION快很多,所以,如果可以确认合并的两个结果集中不包含重复的数据的话,那么就使用UNION ALL,如下:

select * from gc_dfys

union all

select * from ls_jg_dfys

 

 

 

UART 传输一个浮点数

 悬赏分:20- 解决时间:2010-2-4 11:47

UART只能传输一个字节8位的数,想问问大家,如何用UART传输一个浮点数

比方说我现在有个变量是P = 89.432  如何把这个数通过UART传输到电脑上,我的程序是C语言,用的C8051的片子。

谢谢大家了

 

问题补充:

我的硬件平台就是C8051,没有什么特别的啊,一个浮点数要占用4个字节。

想问的就是具体如何拆分啊

有没有具体的做法?

我多给加分

提问者: agassi2002 - 五级

最佳答案

浮点数的表示在计算机里主要遵循ieee754,个别的可能有其内部的表示,这主要是由编译器决定的。

你先看一下,51编译器如何对浮点数的表示。主要是字节的存储顺序。再看一下pc上的编译器浮点数的字节顺序。把传送上到pc上的4个字节,按其顺序拼在一起,即可。如果有问题可发我邮箱。关于浮点数的表示可看以下链接

http://hi.baidu.com/olive1985/blog/item/ea2cd65c56686543fbf2c033.html/cmtid/5892b4c283303d1c0ef47759

主要是阶码和尾数的顺序问题

 

//下面的回答我补充一下

 

union f_data

{

float temp;

unsigned char fdata[4];

}float_data;  //单精度的浮点数,便于拆分字节

//如果是双精度的则定义为

 

//union f_data

//{

//double temp;

//unsigned char fdata[8];

//}double_data;

 

 

//下面为发送单精度浮点数2.5

void send_data(void)

{

float_data.temp=-2.5;

send(float_data.fdata[3]);

send(float_data.fdata[2]);

send(float_data.fdata[1]);

send(float_data.fdata[0]);

}

 

//

//则接收程序如下

void receive_data(void)

{

 

float_data.fdata[3] = receive_byte();

float_data.fdata[2] = receive_byte();

float_data.fdata[1] = receive_byte();

float_data.fdata[0] = receive_byte();

}

//接收到的数据为float_data.temp

//如果两台机器浮点数遵循的标准不一样,则调整一些接受字节的顺序

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值