2016-10-04 40 views
3

我在C中学习函数指针。我了解到函数指针存储函数起点的地址。考虑下面的程序:程序的每一行都有自己的地址吗?

#include <stdio.h> 
void display(); 

int main() 
{ 
void (*ptr)(); 
ptr = &display; 
(*ptr)(); 
return 0; 
} 

void display() 
{ 
printf("hello"); 
} 

如果void display()地址被存储在ptr,那会是怎样的#include <stdio.h>地址等?

+1

虽然dupe被标记为C++,但它也适用于C。如果有人不同意请让我知道。 –

+1

汇编不是线性的转换。源代码只能非常粗略地映射到目标代码。一个函数的开始必然存在并且会有一个地址。然而,编译会使函数体非常难以识别,这就是为什么我们没有反编译器。 – PSkocik

+0

C函数没有指针指向的“起点”;这样的事情出现在实现中。 (例如,函数图像是一系列机器指令,并且指针可能指向最低地址处的第一个指针)。在ISO C标准AFAIR中不需要这样的东西。 – Kaz

回答

3

函数指针通常作为函数入口点的代码地址来实现,但就语言而言,它只是一个不透明的值,可用于调用该函数(并将[in]与相同类型的其他函数指针相等)。它可能是程序范围或系统范围表的索引,并且/或者它可能包含额外的信息。

语言不提供一种方法来查询语句的地址;就C标准而言,这个概念甚至不存在。

如果你想查看生成的机器代码,你可以合理地谈了给定语句生成的代码的地址。例如,您的发言

ptr = &display; 

可能对应于一个MOV指令,并且该指令可能有一个(机器级)的地址,虽然标准的语言给你没有办法使用这些信息。一个goto语句跳转到指定的说法,这是可能与指该语句的第一条指令的计算机地址的指令来实现,但goto标准的描述并没有在详细程度谈论它;它只描述了语义。

一些编译器,包括gcc,有一个扩展(documented here),可以让你把一个标签的地址。但是这只适用于有标签的陈述。

具体地,该指令

#include <stdio.h> 

由编译器的早期阶段,通常被实现为单独的预处理器处理。它引入了一些可以通过下面的代码引用的声明。通常没有生成的代码对应于#include指令,因此谈论它的“地址”是毫无意义的。

而作为PSkocik在评论指出,代码生成不一定是线性的;如果编译器能够以更快的速度对其进行重新排序,则可能没有与给定语句关联的任何代码。 (如果使用gcc扩展来获取标签地址,那么编译器可能会在必要时禁止优化以确保该地址有意义。)

就标准C而言,即使您可以采用一个给定语句的地址,该语言没有任何可以让你做任何事情的构造;例如,标准goto语句仅采用文字标签名称。

+0

也许有一些链接指出C/C++程序如何知道编译和预处理之间的区别,其中include包含在处理中:http://users.cs.cf.ac.uk/Dave.Marshall/C/node3。 html –

+1

@JorgeBellón:就标准而言,预处理只是编译的早期阶段。但是我添加了对预处理器的参考。 –

相关问题