C51语言与汇编语言的关系

来源:互联网 发布:flv parser for mac 编辑:程序博客网 时间:2024/05/17 14:16

C51语言与汇编语言的关系

 

http://wenku.baidu.com/link?url=VkGorJagOh6hGDCB0yzO6CaSSeiMuDOxfW8_ecb8OGfwKcI4CenrIAWug7qjMFoEw3GiXh0vqOkz4edfWUz9xSuZKkfE_ZwEaORNo9XHDwS

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

C语言结构体与联合

 

C基础--结构体成员初始化方式 

之前在linux内核代码中看到结构体成员成员初始化使用类似于.owner = THIS_MODULE, 不太见过,于是搜了个博客,分享下:

转自:http://www.cnblogs.com/Anker/p/3545146.html

1、前言

  今天在公司看一同事写的代码,代码中用到了struct,初始化一个struct用的是乱序格式,如下代码所示:

1 typedef struct _data_t {

2     int a;

3     int b;

4 }data_t;

5 

6 data_t data = {

7    .a = 10,

8    .b = 20,

9 };

 

  通常初始化一个结构体的方式是按序初始化,形如:data_t data={10,20}。感觉很好奇,如是上网百度一下,发现linux下struct初始化可以采用顺序和乱序两种方式,而乱序又有两种不同的形式。本文总结一下struct两种初始化方式的优缺点,并给出完整的测试程序。

2、顺序初始化

  教科书上讲C语言结构体初始化是按照顺序方式来讲的,没有涉及到乱序的方式。顺序初始化struct必须要按照成员的顺序进行,缺一不可,如果结构体比较大,很容易出现错误,而且表现形式不直观,不能一眼看出各个struct各个数据成员的值。

3、乱序初始化

  乱序初始化是C99标准新加的,比较直观的一种初始化方式。相比顺序初始化而言,乱序初始化就如其名,成员可以不按照顺序初始化,而且可以只初始化部分成员,扩展性较好。linux内核中采用这种方式初始化struct。

  乱序初始化有两种方式一种是用点(.)符号,一种是用冒号(:)。方式1是C99标准,方式2是GCC的扩展,强烈建议使用第一种方式。

4、测试程序

 1 /*********************************

 2  * linux下C语言结构体初始化方法

 3  * @author  Anker  @date:2014/02/11

 4  * *******************************/

 5 

 6 #include <stdio.h>

 7 

 8 //函数指针

 9 typedef int (*caculate_cb)(int a, int b);

10 //结构体定义

11 typedef struct _oper {

12     int a;

13     int b;

14     caculate_cb cal_func;

15 } oper;

16 //加法函数定义

17 int add(int a,int b)

18 {

19     return (a+b);

20 }

21 

22 int main()

23 {

24     int ret =0;

25     //顺序初始化结构体1

26     oper oper_one = {10,20, add};

27     //乱序初始化结构体2

28     oper oper_two = {

29         .b = 30,

30         .a = 20,

31         .cal_func = &add,

32     };

33     //乱序初始化结构体3

34     oper oper_three = {

35          cal_func:&add,

36          a:40,

37          b:20,

38     };

39     ret = oper_one.cal_func(oper_one.a, oper_one.b);

40     printf("oper_one caculate: ret = %d\n", ret);

41     ret = oper_two.cal_func(oper_two.a, oper_two.b);

42     printf("oper_two caculate: ret = %d\n", ret);

43     ret = oper_three.cal_func(oper_three.a, oper_three.b);

44     printf("oper_three caculate: ret = %d\n", ret);

45     return 0;

46 }

 

测试结果如下图所示:

5、参考资料

http://blog.csdn.net/adaptiver/article/details/7494081

分类: Misc

 

c语言编程题: 职工数据包括:职工号、职工姓名、性别、年龄、工龄、工资、地址。 (1)为其定义一个结构体变量 (2)根据上述定义的变量,从键盘输入所需要的具体数据,然后通过printf函数显示出来。 (3)定义一个职工数据的结构体数组,从键盘输入每个结构体元素所...展开 

发布于2014-05-27 17:26

最佳答案

#include <stdio.h>
#include <stdlib.h>
#define N 3

struct stuff
{
 int num;
 char name[20];
 char sex;
 int age;
 int work_age;
 float wage;
 char add[30];
};

void input(struct stuff*,int );
void output(struct stuff*,int);

void main()
{
 struct stuff st[N];
 input(st,N);
 output(st,N);
}

void input(struct stuff *s,int n)
{
 int i;
 for(i=0;i<n;i++)
 {
  system("cls");
  printf("请输入第%d个记录\n",i+1);
  printf("编号: ");
  scanf("%d",&s[i].num);
  printf("名字: ");
  scanf("%s",s[i].name);
  printf("性别: ");
  getchar();
  scanf("%c",&s[i].sex);
  printf("年龄: ");
  scanf("%d",&s[i].age);
  printf("工龄: ");
  scanf("%d",&s[i].work_age);
  printf("工资: ");
  scanf("%f",&s[i].wage);
  printf("地址: ");
  scanf("%s",s[i].add);
 }
}

void output(struct stuff *s,int n)
{
 int i;
 printf("编号\t名字\t性别\t年龄\t工龄\t工资\t地址\n");
 printf("----------------------------------------------------\n");
 for(i=0;i<n;i++)
 {
  printf("%d\t%s\t%c\t%d\t%d\t%f\t%s\n",
   s[i].num,s[i].name,s[i].sex,s[i].age,s[i].work_age,s[i].wage,s[i].add);
 }

}

 

联合体union

 当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体(union)。在C          Programming Language 一书中对于联合体是这么描述的:

    1)联合体是一个结构;

    2)它的所有成员相对于基地址的偏移量都为0;

    3)此结构空间要大到足够容纳最"宽"的成员;

    4)其对齐方式要适合其中所有的成员;

下面解释这四条描述:

     由于联合体中的所有成员是共享一段内存的,因此每个成员的存放首地址相对于于联合体变量的基地址的偏移量为0,即所有成员的首地址都是一样的。为了使得所有成员能够共享一段内存,因此该空间必须足够容纳这些成员中最宽的成员。对于这句“对齐方式要适合其中所有的成员”是指其必须符合所有成员的自身对齐方式。

下面举例说明:

如联合体

union U

{

    char s[9];

    int n;

    double d;

};

s占9字节,n占4字节,d占8字节,因此其至少需9字节的空间。然而其实际大小并不是9,用运算符sizeof测试其大小为16.这是因为这里存在字节对齐的问题,9既不能被4整除,也不能被8整除。因此补充字节到16,这样就符合所有成员的自身对齐了。从这里可以看出联合体所占的空间不仅取决于最宽成员,还跟所有成员有关系,即其大小必须满足两个条件:1)大小足够容纳最宽的成员;2)大小能被其包含的所有基本数据类型的大小所整除。 

测试程序:

/*测试联合体  2011.10.3*/

#include <iostream>
using namespace std;

union U1
{
    char s[9];
    int n;
    double d;
};

union U2
{
    char s[5];
    int n;
    double d;
};

int main(int argc,char *argv[])
{
    U1 u1;
    U2 u2;
    printf("%d\n",sizeof(u1));
    printf("%d\n",sizeof(u2));
    printf("0x%x\n",&u1);
    printf("0x%x\n",&u1.s);
    printf("0x%x\n",&u1.n);
    printf("0x%x\n",&u1.d);
    u1.n=1;
    printf("%d\n",u1.s[0]);
    printf("%lf\n",u1.d);
    unsigned char *p=(unsigned char *)&u1;
    printf("%d\n",*p);
    printf("%d\n",*(p+1));
    printf("%d\n",*(p+2));
    printf("%d\n",*(p+3));
    printf("%d\n",*(p+4));
    printf("%d\n",*(p+5));
    printf("%d\n",*(p+6));
    printf("%d\n",*(p+7));
    return 0;
}


输出结果为:

16
8
0x22ff60
0x22ff60
0x22ff60
0x22ff60
1
0.000000
1
0
0
0
48
204
64
0
请按任意键继续. . .

对于sizeof(u1)=16。因为u1中s占9字节,n占4字节,d占8字节,因此至少需要9字节。其包含的基本数据类型为char,int,double分别占1,4,8字节,为了使u1所占空间的大小能被1,4,8整除,则需填充字节以到16,因此sizeof(u1)=16.

对于sizeof(u2)=8。因为u2中s占5字节,n占4字节,d占8字节,因此至少需要8字节。其包含的基本数据类型为char,int,double分别占1,4,8字节,为了使u2所占空间的大小能被1,4,8整除,不需填充字节,因为8本身就能满足要求。因此sizeof(u2)=8。

从打印出的每个成员的基地址可以看出,联合体中每个成员的基地址都相同,等于联合体变量的首地址。

u1.n=1,将u1的n赋值为1后,则该段内存的前4个字节存储的数据为00000001 00000000 00000000 00000000

因此取s[0]的数据表示取第一个单元的数据,其整型值为1,所以打印出的结果为1.

至于打印出的d为0.000000愿意如下。由于已知该段内存前4字节的单元存储的数据为00000001 00000000 00000000 00000000,从上面打印结果48,204,64,0可以知道后面4个字节单元中的数据为00110000 11001100 01000000 00000000,因此其表示的二进制浮点数为

00000000 01000000 11001100 00110000 00000000 00000000 00000000 00000001

对于double型数据,第63位0为符号位,62-52 00000000100为阶码,0000 11001100 00110000 00000000 00000000 00000000 00000001为尾数,根据其值知道尾数值约为0,而阶码为4-1023=-1019,因此其表示的浮点数为1.0*2^(-1019)=0.00000000000......,因此输出结果为0.000000。

 

原创粉丝点击