内存地址 | 存放内容 |
0x4000 | 0x78 |
0x4001 | 0x56 |
0x4002 | 0x34 |
0x4003 | 0x12 |
内存地址 | 存放内容 |
0x4000 | 0x12 |
0x4001 | 0x34 |
0x4002 | 0x56 |
0x4003 | 0x78 |
联合体union的存放顺序是所有成员都从低地址开始存放,利用该特性就可以轻松地获得了CPU对内存采用Little-endian还是Big-endian模式读写。
测试代码:
int isLittleEndian()
{
union _dword
{
int all;
struct _bytes
{
char byte0;/*对little来说是最低位,而对big则是最高位*/
char pad[3];
}bytes;
}dword;
dword.all=0x87654321;/*all的功能就是给dword四个字节赋值*/
return (0x21==dword.bytes.byte0);/*查看第一个字节*/
}
分析: 如果你的处理器调用函数isLittleEndian返回1,那么说明你的处理器为little endian,否则为big endian.注意,如果在little endian处理器上,byte0和pad按内存从低到高的存放顺序:LOW->byte0 pad[0] pad[1] pad[2] ->HIGH;0x87654321按内存从低到高的存放顺序: 0x21 0x43 0x65 0x87, 可见byte0对应到0x21。所以通过判断dword中第一个字节dword.bytes.byte0是否与0x21相等就可以看出是否是little endian。
{
unsigned int all;/*all可以同时清理或设置info中的所有内容*/
struct
{
unsigned int pad: 7;
unsigned int used: 1;/*高位*/
unsigned int personal_id: 8;
unsigned int class_id: 3;
unsigned int subject_id: 6;
unsigned int score: 7;/*低位*/
}info;
}student;
unsigned int students;
unsigned int student_database[MAX_STUDENT_NUM]={0};
int find_from_database(unsigned int personal_id);
int delete_from_database(unsigned int personal_id);
void print_database(void);
void print_student(unsigned int data);
int add_to_database(unsigned int data)
{
student stu;
int i;
for(i=0;i<MAX_STUDENT_NUM;i++)
{
stu.all = student_database[i];
if(!stu.info.used)
{
stu.all = data;
stu.info.used = 1;
student_database[i] = stu.all;
return 1;
}
}
return 0;
}
int find_from_database(unsigned int personal_id)
{
student stu;
int i;
for(i=0;i<MAX_STUDENT_NUM;i++)
{
stu.all = student_database[i];
if(stu.info.used && stu.info.personal_id==personal_id)
{
return stu.all;
}
}
return -1;
}
void print_student(unsigned int data)
{
student stu;
stu.all = data;
printf("personal id %d,class id %d,subject id %d,score %d/n",
stu.info.personal_id,stu.info.class_id,stu.info.subject_id,
}
void print_database(void)
{
student stu;
int i;
for(i=0;i<MAX_STUDENT_NUM;i++)
{
stu.all = student_database[i];
if(stu.info.used)
{
print_student(stu.all);
}
}
}
int main(int argc, char *argv[])
{
student jack,jone;
jack.all = 0;
jack.info.personal_id = 102;
jack.info.class_id = 2; /*class 2*/
jack.info.subject_id = 2; /*English*/
jack.info.score = 50; /*fouled*/
jone.info.personal_id = 88;
jone.info.class_id = 2; /*calss 2*/
jone.info.subject_id = 2; /*English*/
jone.info.score = 73; /*passed*/
add_to_database(jone.all);
jack.all = find_from_database(jack.info.personal_id);
if(jack.all<0)
{
printf("no such student with id %d/n",jone.info.personal_id);
}
else
{
printf("found! ");
print_student(jack.all);
}
print_database();
}
personal id 102,class id 2,subject id 2,score 50
personal id 88,class id 2,subject id 2,score 73
在涉及音视频编解码算法中,经常会涉及一些数据压缩、声音解码、图象的缩放等问题。
这里通过一个例子来推荐一种union绝妙用法(这种方法由Equator公司提供,在我们公司的图象处理算法中用得很多)。在该例子中,利用union结构n64u实现占8个字节n64类型与单字节的c0~c7的相互转换,从而达到数据压缩和分解的目的。
#define OUT
#define INOUT
typedef unsigned int n32;
typedef unsigned short n16;
typedef unsigned char n8;
unsigned char c0, c1, c2, c3, c4, c5, c6, c7;
}s8t;
n64 n64;
n32 l0, l1;
} u32;
long l0, l1;
} s32;
unsigned short s0, s1, s2, s3;
} u16;
short s0, s1, s2, s3;
} s16;
unsigned char c0, c1, c2, c3, c4, c5, c6, c7;
} u8;
char c0, c1, c2, c3, c4, c5, c6, c7;
} s8;
} n64u;
int uncompress8_64(IN const n8* src,IN n16 n,OUT n64* dst);
{
n64u n64u_data;
register n64* n64ptr=(n64*)src;
register n8* n8ptr=dst;
n16 i=0,num=n;
{
printf("invalid param,src 0x%x,dst 0x%x,n %d/n",n64ptr,n8ptr,n);
return 0;
}
for(i=0;i<num;i++)
{
n64u_data.n64 = *n64ptr++;
/*用简单的均值法将8个点压缩成1个点*/
*n8ptr++ = (n64u_data.u8.c0+n64u_data.u8.c1+n64u_data.u8.c2+/
n64u_data.u8.c3+n64u_data.u8.c4+n64u_data.u8.c5+/
n64u_data.u8.c6+n64u_data.u8.c7)/(sizeof(n64)/sizeof(n8));
}
return 1;
}
{
n64u n64u_data;
register n64* n64ptr=dst;
register n8* n8ptr=(n8*)src;
register n8 n8data;
n16 i=0,num=n;
if(NULL==n64ptr || NULL==n8ptr || n<1)
{
printf("invalid param,src 0x%x,dst 0x%x,n %d/n",n64ptr,n8ptr,n);
return 0;
}
for(i=0;i<num;i++)
{
n8data=*n8ptr++;
/*将1个点解压成8个点,采用简单的还原,所以有失真*/
n64u_data.u8.c0 = n8data;
n64u_data.u8.c1 = n8data;
n64u_data.u8.c2 = n8data;
n64u_data.u8.c3 = n8data;
n64u_data.u8.c4 = n8data;
n64u_data.u8.c5 = n8data;
n64u_data.u8.c6 = n8data;
n64u_data.u8.c7 = n8data;
*n64ptr++ = n64u_data.n64;
}
}
int main(int argc, char *argv[])
{
n64 n64data[MAX_DATA_COMPRESSED_NUM];
n8 n8data[MAX_DATA_COMPRESSED_NUM];
s8t s8t_data[MAX_DATA_COMPRESSED_NUM]
=
{/*即将被压缩的数据,一个数据占一个字节*/
{1,2,3,4,5,6,7,8},/*8个字节被压缩成单个字节*/
{2,2,3,4,5,6,7,7},
{3,2,3,4,5,6,7,6},
{4,2,3,4,5,6,7,5},
{5,2,3,4,5,6,7,4},
{6,2,3,4,5,6,7,3},
{7,2,3,4,5,6,7,2},
{8,7,6,5,4,3,2,1}
};
n16 i,n=MAX_DATA_COMPRESSED_NUM;
printf("data:/n");
for(i=0;i<n;i++)
{
n64data[i] = *(n64*)&s8t_data[i];
printf("%3u %3u %3u %3u %3u %3u %3u %3u/n",
}
printf("/n");
compress64_8(n64data,n,n8data);
printf("compressed to:/n");
for(i=0;i<n;i++)
{
printf("%3u ",n8data[i]);
}
printf("/n/n");
uncompress8_64(n8data,n,n64data);
printf("uncompressed to:/n");
for(i=0;i<n;i++)
{
*(n64*)&s8t_data[i] = n64data[i];
printf("%3u %3u %3u %3u %3u %3u %3u %3u/n",
}
printf("/n");
}
运行结果:
data:
1 2 3 4 5 6 7 8
2 2 3 4 5 6 7 7
3 2 3 4 5 6 7 6
4 2 3 4 5 6 7 5
5 2 3 4 5 6 7 4
6 2 3 4 5 6 7 3
7 2 3 4 5 6 7 2
8 7 6 5 4 3 2 1
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
4 4 4 4 4 4 4 4
*/
{
unsigned int struct_id
{
struct my_struct_1;
struct my_struct_2;
struct my_struct_3;
* /brief 来自编码器的音频数据的缓冲区信息
*/
typedef struct
{
int codecId; /**< codec ID */
int packetNum; /**< 该帧数据一共有多少个包 */
int actualNum; /**< 当前已存入的包数 */
int packetLen; /**< 正常数据包最大长度,包括包头 */
int leftPacketLen; /**< 最后一个数据包大小,包括包头 */
int frameSample; /**< 0x00表示8kHz,0x01表示11kHz*/
int timeStamp; /**< 表示该帧的编码时间 */
int dataLen; /**< 数据长度,包括包头 */
int ready; /**< 该帧数据的数据包是否都已经写入*/
unsigned char* buffer; /**< 数据指针 */
int reserve1; /**< 保留位,用0填充 */
} TABufferInfoFromCodec;
* /brief 来自编码器的视频数据的缓冲区信息
*/
typedef struct
{
int codecId; /**< codec ID */
int bKeyFrame; /**< TRUE:关键帧 */
int packetNum; /**< 该帧数据一共有多少个包 */
int actualNum; /**< 当前已存入的包数 */
int packetLen; /**< 正常数据包最大长度,包括包头 */
int leftPacketLen; /**< 最后一个数据包大小,包括包头 */
int timeStamp; /**< 表示该帧的编码时间 */
int dataLen; /**< 数据长度,包括包头 */
int ready; /**< 该帧数据的数据包是否都已经写入*/
unsigned char* buffer; /**< 数据指针 */
int reserve1; /**< 保留位,用0填充 */
} TVBufferInfoFromCodec;
* /brief 来自网络的视频数据的缓冲区信息
*/
typedef struct
{
int codecId;
int bKeyFrame;
int packetNum;
int actualNum;
int packetLen;
int leftPacketLen;
int rtpLen;
int timeStamp;
int firstSquence;
int dataLen;
int ready;
unsigned char* buffer;
} TVBufferInfoToCodec;
* /brief 来自网络的音频数据的缓冲区信息
*/
typedef struct
{
int codecId;
int packetNum;
int actualNum;
int packetLen;
int leftPacketLen;
int rtpLen;
int timeStamp;
int firstSquence;
int dataLen;
int ready;
unsigned char* buffer;
int reserve1;
} TABufferInfoToCodec;
* /brief 数据缓冲区信息结构
*/
typedef struct
{
int bufferType;
union
{
TVBufferInfoFromCodec bufferInfoFromVCoder;
TABufferInfoFromCodec bufferInfoFromACoder;
TVBufferInfoToCodec bufferInfoFromVNetWork;
TABufferInfoToCodec bufferInfoFromANetWork;
} buffer_info;
} TFrameBufferInfo;
int send_to(void* stream)
{
/*省略*/
}
TVBufferInfoFromCodec* pVBufferInfoFromCodec;
unsigned char buffer[1200*5];/*最大存放5个数据包*/
/*假设你要向网络发送一段视频数据,音频接收为1,
视频接收为2,*音频发送为3,视频发送为4*/
tFrameBufferInfo.bufferType=4;
pVBufferInfoFromCodec
=&tFrameBufferInfo.buffer_info.bufferInfoFromVCoder;
pVBufferInfoFromCodec->bKeyFrame = 1;
pVBufferInfoFromCodec->packetNum = 2;
pVBufferInfoFromCodec->actualNum = 2;
pVBufferInfoFromCodec->leftPacketLen = 123;
pVBufferInfoFromCodec->dataLen = 1323;
pVBufferInfoFromCodec->ready = 1;
pVBufferInfoFromCodec->buffer = buffer;
send_to((void*)&tFrameBufferInfo);