rip c语言,『C语言学习笔记』extern真恶心

extern

在C语言中,一个文件中声明的全局变量和函数是默认以"extern"声明的,是外部文件可见的.

int x = 1;

int foo(int var)

{

return var + x;

}

// 等价于

extern int x = 1; // 但是这句产生编译器警告,和"extern int x;"引用外部的x非常容易混淆.

extern int foo(int var)

{

return var + x;

}

一个文件中以"static"声明的变量和函数是外部文件不可见的.

static int x = 1; // 仅仅是本文件范围的变量

static int foo(int var) // 仅仅是本文件范围的函数

{

return var + x;

}

由于"static"是对于外部范围不可见的,所以可以用"static"声明和外部函数同名的函数,但不要在同一范围使用.

static int x = 1;

int bar()

{

static int x = 2;

{

prinf("%d", x);

static int x = 3;

prinf("%d", x);

}

return x;

}

上述的三个静态x都会被分配内存,编译器会使用三个不同的标号:

x:

.long 1

x.1234:

.long 2

x.1235:

.long 3

bar:

...

movl x.1234(%rip), %esi

...

call printf

...

movl x.1235(%rip), %esi

...

movl x.1234(%rip), %eax

虽然三个x在汇编中没有任何的区别,但是C编译器是按照源文件的逻辑来使用变量的:1.先在所在的周期范围查找;2.再在更大的周期范围一步一步向上查找.所以第一个printf打印2,第二个printf打印3,返回值为2.

从外部引用变量和函数.

tool.c

float var = 1000.11;

int func(int a, int b)

{

return a + b;

}

=================================================

main.c

extern float var; // 不要是"extern int big_num = 1",这样是声明不是引用.

extern int func(int, int);

float main ()

{

func(1, 2);

return var;

}

如果没有"extern int var;".

extern int func(int, int);

float main ()

{

func(1, 2);

return var;

}

凭空岀现的var无法通过C编译器.

如果没有"extern int func(int, int);".

extern float var;

float main ()

{

func(1, 2);

// 或者 int a = func(1, 2);都一样

return var;

}

是可以通过C编译器的,因为"func(1, 2);"不需要函数原型就可以编译成:

movl $2, %esi

movl $1, %edi

call func

所以通过C编译器是应该的.但是没有了函数原型的限制func函数多次使用写错了也是可以通过C编译器的.

extern float var;

float main ()

{

func(1, 2);

func(1);

func();

func(1, 2, 3, 4);

return var;

}

因为C编译器根本不知道func的原型是不是可变参数.

邪门歪道

交换了var和func能不能通过C编译和汇编?能,因为在链接之前两个文件是不见面的,自己过自己的.能不能通过链接?

tool.c

float var = 1000.11;

int func(int a, int b)

{

return a + b;

}

=================================================

main.c

extern float func;

extern int var(int, int);

float main ()

{

var(1, 2);

return func;

}

能,因为main.c通过C编译器的得到的汇编文件中只是用func和var符号完成指令:

movl $2, %esi

movl $1, %edi

call var

mov func(%rip), %xmm0

但是不会分配内存.这样在通过汇编器得到可重定向文件时,使用var和func的地方被写入.rel .data和.rel .text重定向表, 在.symtab符号表中var和func被标记为NOTYPE,因为汇编文件中并没有var和func的主体,只是平平无奇的两个内存地址.

链接器是纯洁的,只做重定向,从不怀疑.链接tool.o和main.o时,查找tool.o符号表中符号名称为var和func符号对应的内存地址去重定向main.o中的var和func,使得main.c中的var函数是tool.c中var变量的地址,func变量是tool.c中func函数的地址.

总结:

extern用来声明定义外部可见的变量或函数,在汇编文件中用.global伪指令标记,在可重定向文件的符号表中用global标记;static用来声明定义外部不可见的变量或函数,在汇编文件中用.local伪指令标记,在可重定向文件的符号表中用local标记;

extern用来引用外部的变量或函数,在汇编文件中只使用变量或函数的符号,但不给符号分配任何内存,在可重定向文件中和符号有关的位置都被写入重定向表.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用C写的rip协议 这是其中的广播request程序片段: void RouteInit() { int i,optval=0,length,error; routeNum = 0; // init local socket address and ip address GetLocalIP(); // init route table items for(i = 0; i < MAX_NUM; i++) { SetRouteEntry(&routeTable[i].routeInfo,"0.0.0.0",0,0); routeTable[i].isvalid = 0; routeTable[i].timer = 0; routeTable[i].statue = 0; inet_aton("0,0,0,0",&routeTable[i].sourceIPAddr); } // init request packet SetRoutePacket(&reqPacket,REQUEST); SetRouteEntry(&reqPacket.routeEntry[0],"0.0.0.0",0,16); // init response packet SetRoutePacket(&resPacket,RESPONSE); recvSockAddr.sin_family = AF_INET; recvSockAddr.sin_port = htons(PORT); recvSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); sendSockAddr.sin_family = AF_INET; sendSockAddr.sin_port = htons(PORT); // inet_aton("240.255.255.255",&sendSockAddr.sin_addr); sendSockAddr.sin_addr.s_addr = htonl(INADDR_ANY); EntryInit(); sock = socket(AF_INET,SOCK_DGRAM,0); if(sock<0) { printf("cannot create a socket!\n"); exit(1); } if(setsockopt(sock,SOL_SOCKET,SO_BROADCAST,&optval,sizeof(int)) != 0) { printf("cannot broadcast!\n"); close(sock); exit(1); } if(bind(sock,(struct sockaddr*)&recvSockAddr,sizeof(recvSockAddr))<0) { printf("cannot bind to port\n"); close(sock); exit(1); } length=sizeof recvSockAddr; getsockname(sock,(struct sockaddr*)&recvSockAddr,&length); printf("Port %d is opened. Listen for packet...\n",ntohs(recvSockAddr.sin_port)); FD_ZERO(&fdSet); FD_SET(sock,&fdSet); error = sendto(sock,&reqPacket,4+sizeof(struct ROUTE_ENTRY),0,(struct sockaddr*)(&sendSockAddr),sizeof(struct sockaddr)); if(error<0) { PrintEntry(&reqPacket.routeEntry[0]); printf("broadcast request packet failed! %d,%d,%d\n",error,sock,fdSet); } }

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值