【编译、链接、装载十六】汇编与指针、汇编与new

这篇具有很好参考价值的文章主要介绍了【编译、链接、装载十六】汇编与指针、汇编与new。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

简介:我们从预处理、编译、汇编、编译、链接、装载一路走到现在,一直在c语言的层面分析,原因还是这些知识太苦涩,理解时需要看下具体的反汇编代码,且c++的反汇编更难理解些,所以,c语言的入手比c++入手更简单和更好理解些。在这个系列的结尾,我们从汇编层面分析下c++ new的过程、c++类的初始化过程、类的成员函数调用过程。另外再从汇编层面看下c语言的指针是怎么工作的。

一、汇编与指针

1、普通指针

普通指针:普通变量的指针(除char)

  1. demo
#include <stdio.h>
void show(int *ptr)
{
	int temp = *ptr;
	printf("the number is: %d\n",temp);	
}

int main() 
{
	int a = 3;
      int * ptr = &a;
	show(ptr);
      return 0;
}
  1. 编译、执行、反汇编
[root@localhost test01_putongzhizhen]# gcc main.c
[root@localhost test01_putongzhizhen]# ./a.out
the number is: 3
[root@localhost test01_putongzhizhen]# objdump -d -x ./a.out

000000000040052d <show>:
  40052d:	55                   	push   %rbp
  40052e:	48 89 e5             	mov    %rsp,%rbp
  400531:	48 83 ec 20          	sub    $0x20,%rsp
  400535:	48 89 7d e8          	mov    %rdi,-0x18(%rbp)
  400539:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  40053d:	8b 00                	mov    (%rax),%eax
  40053f:	89 45 fc             	mov    %eax,-0x4(%rbp)
  400542:	8b 45 fc             	mov    -0x4(%rbp),%eax
  400545:	89 c6                	mov    %eax,%esi
  400547:	bf 20 06 40 00       	mov    $0x400620,%edi
  40054c:	b8 00 00 00 00       	mov    $0x0,%eax
  400551:	e8 ba fe ff ff       	callq  400410 <printf@plt>
  400556:	c9                   	leaveq 
  400557:	c3                   	retq   

0000000000400558 <main>:
  400558:	55                   	push   %rbp
  400559:	48 89 e5             	mov    %rsp,%rbp
  40055c:	48 83 ec 10          	sub    $0x10,%rsp
  400560:	c7 45 f4 03 00 00 00 	movl   $0x3,-0xc(%rbp)
  400567:	48 8d 45 f4          	lea    -0xc(%rbp),%rax
  40056b:	48 89 45 f8          	mov    %rax,-0x8(%rbp)
  40056f:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
  400573:	48 89 c7             	mov    %rax,%rdi
  400576:	e8 b2 ff ff ff       	callq  40052d <show>
  40057b:	b8 00 00 00 00       	mov    $0x0,%eax
  400580:	c9                   	leaveq 
  400581:	c3                   	retq   
  400582:	66 2e 0f 1f 84 00 00 	nopw   %cs:0x0(%rax,%rax,1)
  400589:	00 00 00 
  40058c:	0f 1f 40 00          	nopl   0x0(%rax
  1. main
  • 在 x86 汇编中,括号 () 被用来表示寻址,也就是通过某个地址访问该地址存储的内容。例如,(%rax) 表示使用寄存器 %rax 存储的地址所对应的内存单元的值。
  • LEA(Load Effective Address,加载有效地址)是一种 x86 汇编指令,用于将一个内存地址的有效地址(即相对于段基址的偏移量)加载到寄存器中。它的语法如下:
LEA destination, source

其中,destination 是目标操作数,source 是源操作数。指令的作用是将 source 的地址计算出来,并将其存储在 destination 中。

 x86-64 汇编的 main 函数,其作用是调用另一个函数 show 并将其返回值存储在 %eax 寄存器中,并最终返回 0。
下面是各条指令的解释:

  1. push %rbp:将当前栈帧的基址寄存器 %rbp 压入栈中,为函数的局部变量和参数预留空间。

  2. mov %rsp, %rbp:将栈顶指针寄存器 %rsp 的值赋给 %rbp,以此建立栈帧。

  3. sub $0x10, %rsp:在栈上分配 16 字节的内存,以此存储该函数的局部变量和参数。

  4. movl $0x3,-0xc(%rbp):将立即数 3 存储到相对于 %rbp 偏移量为 -0xc 的内存位置中,相当于声明了一个名为 x 的 int 变量并且初始化为 35. lea -0xc(%rbp),%rax:计算出相对于 %rbp 偏移量为 -0xc 的内存地址,并将其存储到通用寄存器 %rax 中。
 
  6. mov %rax,-0x8(%rbp):将 %rax 中存储的地址存储到相对于 %rbp 偏移量为 -0x8 的内存位置中,相当于声明了一个名为 p 的指针变量并且将其初始化为指向 x 的地址。
  
  8. mov -0x8(%rbp),%rax:将相对于 %rbp 偏移量为 -0x8 的内存地址中存储的值(即指向 x 的地址)存储到通用寄存器 %rax 中。

  9. mov %rax,%rdi:将 %rax 中存储的地址存储到参数寄存器 %rdi 中,准备传递给 show 函数。

  10. callq 40052d <show>:调用 show 函数,并将其返回值存储在 %eax 寄存器中。

  11. mov $0x0,%eax:将立即数 0 存储到 %eax 中,作为函数的返回值。

  12. leaveq:恢复栈帧基址并弹出栈顶指针,表示该函数的执行结束。

  13. retq:返回到调用者的地址,并将栈指针调整至原来的位置。
  1. show

这是一段x86_64汇编代码,其函数名为show,具体内容如下:

首先,该函数执行了一些准备工作,包括将rbp寄存器的值压入栈中(push %rbp),将rsp寄存器的值存储在rbp寄存器中(mov %rsp,%rbp),以及分配了20个字节的空间用于存储局部变量(sub $0x20,%rsp)。

然后,函数将传入的第一个参数(即调用该函数时传进来的指针)存储在函数栈帧中的-0x18(%rbp)位置(mov %rdi,-0x18(%rbp))。

接着,函数将存储在-0x18(%rbp)位置的指针赋值给rax寄存器(mov -0x18(%rbp),%rax)。

然后,函数从rax寄存器中取出指针指向的内存地址处的值(mov (%rax),%eax)并将其存储在函数栈帧中的-0x4(%rbp)位置。

函数接着从-0x4(%rbp)位置取出该值(mov -0x4(%rbp),%eax),并将其保存在esi寄存器中(mov %eax,%esi)。

然后,函数将另一个值(即0x400620)存储在edi寄存器中(mov $0x400620,%edi)。

接着,函数调用printf函数(callq 400410 printf@plt)并将参数传递给它(第一个参数esi,第二个参数edi)。这里的printf函数是程序中另一个地方定义的,不在本段代码范围内。

最后,函数清除栈帧(leaveq)并返回(retq)。

总之,该函数的作用是从传入的指针指向的内存位置中读取一个值,并将其作为参数传递给printf函数进行输出。

2、字符串常量指针

字符串常量指针:字符串常量本身就是一个地址!

  1. demo
#include <stdio.h>
//#include<cstring>
void show(char *ptr)
{
	char *temp ;
	temp = ptr;
	printf("the char * is: %s\n",ptr);	
}

int main() 
{
	char chr[20] = "hello world!\n";
      char * ptr = chr;
	show(ptr);
      return 0;
}
  1. 编译、执行、反汇编

大家可以参考上面的,自己一句句的分析下。

[root@localhost test01_zz_str]# gcc main.c
[root@localhost test01_zz_str]# ./a.out
the char * is: hello world!

[root@localhost test01_zz_str]# objdump -d -x ./a.out

000000000040052d <show>:
  40052d:	55                   	push   %rbp
  40052e:	48 89 e5             	mov    %rsp,%rbp
  400531:	48 83 ec 20          	sub    $0x20,%rsp
  400535:	48 89 7d e8          	mov    %rdi,-0x18(%rbp)
  400539:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  40053d:	48 89 45 f8          	mov    %rax,-0x8(%rbp)
  400541:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  400545:	48 89 c6             	mov    %rax,%rsi
  400548:	bf 30 06 40 00       	mov    $0x400630,%edi
  40054d:	b8 00 00 00 00       	mov    $0x0,%eax
  400552:	e8 b9 fe ff ff       	callq  400410 <printf@plt>
  400557:	c9                   	leaveq 
  400558:	c3                   	retq   

0000000000400559 <main>:
  400559:	55                   	push   %rbp
  40055a:	48 89 e5             	mov    %rsp,%rbp
  40055d:	48 83 ec 20          	sub    $0x20,%rsp
  400561:	48 b8 68 65 6c 6c 6f 	movabs $0x6f77206f6c6c6568,%rax
  400568:	20 77 6f 
  40056b:	48 89 45 e0          	mov    %rax,-0x20(%rbp)
  40056f:	48 b8 72 6c 64 21 0a 	movabs $0xa21646c72,%rax
  400576:	00 00 00 
  400579:	48 89 45 e8          	mov    %rax,-0x18(%rbp)
  40057d:	c7 45 f0 00 00 00 00 	movl   $0x0,-0x10(%rbp)
  400584:	48 8d 45 e0          	lea    -0x20(%rbp),%rax
  400588:	48 89 45 f8          	mov    %rax,-0x8(%rbp)
  40058c:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
  400590:	48 89 c7             	mov    %rax,%rdi
  400593:	e8 95 ff ff ff       	callq  40052d <show>
  400598:	b8 00 00 00 00       	mov    $0x0,%eax
  40059d:	c9                   	leaveq 
  40059e:	c3                   	retq   
  40059f:	90                   	nop

二、汇编与new

1、demo


#include <iostream>
#include<cstring>
using namespace std;
class Person
{
public:
	Person(int age)
	{
		m_age = age;
		printf("Person 构造完成\n");
	}
	~Person(){printf("Person 析构完成\n");}

public:
	void speak()
	{	
		// cout<<"my name is "<<m_name<<"my age is "<<m_age<<endl;
		printf("my name is %s,\nmy age is %d\n",m_name,m_age);
	};
private:
	const char* m_name = "junxue" ;
	int m_age;
};

int main() 
{
	Person* jun = new Person(18);
	// use
	jun->speak();

	delete jun;
      return 0;
}
  1. 编译、执行、反汇编

备注:为了分析主要的几个点,我删除了部分反汇编的代码。

[root@localhost test04new]# g++ -std=c++11 main.cpp
[root@localhost test04new]# ./a.out
Person 构造完成
my name is junxue,
my age is 18
Person 析构完成
[root@localhost test04new]# objdump -d -x ./a.out

00000000004006e0 <_ZdlPv@plt>:
  4006e0:	ff 25 4a 09 20 00    	jmpq   *0x20094a(%rip)        # 601030 <_ZdlPv@GLIBCXX_3.4>
  4006e6:	68 03 00 00 00       	pushq  $0x3
  4006eb:	e9 b0 ff ff ff       	jmpq   4006a0 <.plt>

0000000000400740 <_Znwm@plt>:
  400740:	ff 25 1a 09 20 00    	jmpq   *0x20091a(%rip)        # 601060 <_Znwm@GLIBCXX_3.4>
  400746:	68 09 00 00 00       	pushq  $0x9
  40074b:	e9 50 ff ff ff       	jmpq   4006a0 <.plt>

000000000040084d <main>:
  40084d:	55                   	push   %rbp
  40084e:	48 89 e5             	mov    %rsp,%rbp
  400851:	41 54                	push   %r12
  400853:	53                   	push   %rbx
  400854:	48 83 ec 10          	sub    $0x10,%rsp
  400858:	bf 10 00 00 00       	mov    $0x10,%edi
  40085d:	e8 de fe ff ff       	callq  400740 <_Znwm@plt>
  400862:	48 89 c3             	mov    %rax,%rbx
  400865:	be 12 00 00 00       	mov    $0x12,%esi
  40086a:	48 89 df             	mov    %rbx,%rdi
  40086d:	e8 a2 00 00 00       	callq  400914 <_ZN6PersonC1Ei>
  400872:	48 89 5d e8          	mov    %rbx,-0x18(%rbp)
  400876:	48 8b 45 e8          	mov    -0x18(%rbp),%rax
  40087a:	48 89 c7             	mov    %rax,%rdi
  40087d:	e8 da 00 00 00       	callq  40095c <_ZN6Person5speakEv>
  400882:	48 8b 5d e8          	mov    -0x18(%rbp),%rbx
  400886:	48 85 db             	test   %rbx,%rbx
  400889:	74 10                	je     40089b <main+0x4e>
  40088b:	48 89 df             	mov    %rbx,%rdi
  40088e:	e8 b1 00 00 00       	callq  400944 <_ZN6PersonD1Ev>
  400893:	48 89 df             	mov    %rbx,%rdi
  400896:	e8 45 fe ff ff       	callq  4006e0 <_ZdlPv@plt>
  40089b:	b8 00 00 00 00       	mov    $0x0,%eax
  4008a0:	eb 16                	jmp    4008b8 <main+0x6b>
  4008a2:	49 89 c4             	mov    %rax,%r12
  4008a5:	48 89 df             	mov    %rbx,%rdi
  4008a8:	e8 33 fe ff ff       	callq  4006e0 <_ZdlPv@plt>
  4008ad:	4c 89 e0             	mov    %r12,%rax
  4008b0:	48 89 c7             	mov    %rax,%rdi
  4008b3:	e8 98 fe ff ff       	callq  400750 <_Unwind_Resume@plt>
  4008b8:	48 83 c4 10          	add    $0x10,%rsp
  4008bc:	5b                   	pop    %rbx
  4008bd:	41 5c                	pop    %r12
  4008bf:	5d                   	pop    %rbp
  4008c0:	c3                   	retq   

0000000000400914 <_ZN6PersonC1Ei>:
  400914:	55                   	push   %rbp
  400915:	48 89 e5             	mov    %rsp,%rbp
  400918:	48 83 ec 10          	sub    $0x10,%rsp
  40091c:	48 89 7d f8          	mov    %rdi,-0x8(%rbp)
  400920:	89 75 f4             	mov    %esi,-0xc(%rbp)
  400923:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
  400927:	48 c7 00 21 0a 40 00 	movq   $0x400a21,(%rax)
  40092e:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
  400932:	8b 55 f4             	mov    -0xc(%rbp),%edx
  400935:	89 50 08             	mov    %edx,0x8(%rax)
  400938:	bf 28 0a 40 00       	mov    $0x400a28,%edi
  40093d:	e8 8e fd ff ff       	callq  4006d0 <puts@plt>
  400942:	c9                   	leaveq 
  400943:	c3                   	retq   

0000000000400944 <_ZN6PersonD1Ev>:
  400944:	55                   	push   %rbp
  400945:	48 89 e5             	mov    %rsp,%rbp
  400948:	48 83 ec 10          	sub    $0x10,%rsp
  40094c:	48 89 7d f8          	mov    %rdi,-0x8(%rbp)
  400950:	bf 3c 0a 40 00       	mov    $0x400a3c,%edi
  400955:	e8 76 fd ff ff       	callq  4006d0 <puts@plt>
  40095a:	c9                   	leaveq 
  40095b:	c3                   	retq   

000000000040095c <_ZN6Person5speakEv>:
  40095c:	55                   	push   %rbp
  40095d:	48 89 e5             	mov    %rsp,%rbp
  400960:	48 83 ec 10          	sub    $0x10,%rsp
  400964:	48 89 7d f8          	mov    %rdi,-0x8(%rbp)
  400968:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
  40096c:	8b 50 08             	mov    0x8(%rax),%edx
  40096f:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
  400973:	48 8b 00             	mov    (%rax),%rax
  400976:	48 89 c6             	mov    %rax,%rsi
  400979:	bf 50 0a 40 00       	mov    $0x400a50,%edi
  40097e:	b8 00 00 00 00       	mov    $0x0,%eax
  400983:	e8 28 fd ff ff       	callq  4006b0 <printf@plt>
  400988:	c9                  	leaveq 
  400989:	c3                   	retq   
  40098a:	66 0f 1f 44 00 00    	nopw   0x0(%rax,%rax,1)
  1. main主函数汇编分析

main汇编分析如下,主要要以下5个过程

  • 第一步:new,分配内存——_Znwm@plt
  • 第二步:new,Person类的构造函数——_ZN6PersonC1Ei
  • 第三步:调用Person->speak函数——_ZN6Person5speakEv
  • 第四步:调用Person类的析构函数——_ZN6PersonD1Ev
  • 第五步:释放new分配的内存——ZdlPv@plt
  1. Person的构造函数——_ZN6PersonC1Ei

从Person的构造函数我们可以知道,Person类的初始化只有和成员变量初始化相关的,和成员函数无关。

  • 结论:类的大小只和成员变量的个数和成员变量的大小有关。和成员函数无关。
0000000000400914 <_ZN6PersonC1Ei>:
  400914:	55                   	push   %rbp
  400915:	48 89 e5             	mov    %rsp,%rbp
  400918:	48 83 ec 10          	sub    $0x10,%rsp
  40091c:	48 89 7d f8          	mov    %rdi,-0x8(%rbp)
  400920:	89 75 f4             	mov    %esi,-0xc(%rbp)
  400923:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
  400927:	48 c7 00 21 0a 40 00 	movq   $0x400a21,(%rax)
  40092e:	48 8b 45 f8          	mov    -0x8(%rbp),%rax
  400932:	8b 55 f4             	mov    -0xc(%rbp),%edx
  400935:	89 50 08             	mov    %edx,0x8(%rax)
  400938:	bf 28 0a 40 00       	mov    $0x400a28,%edi
  40093d:	e8 8e fd ff ff       	callq  4006d0 <puts@plt>
  400942:	c9                   	leaveq 
  400943:	c3                   	retq   
  1. Person的成员函数——_ZN6Person5speakEv

当我们调用类的成员函数时

jun->speak();

其实是去找到类的成员函数地址去执行了,speak函数地址是

000000000040095c <_ZN6Person5speakEv>:

将隐式传递的第一个参数(即this指针)存储到堆栈上的-0x8(%rbp)处。由于this指针存储了对象的地址,因此在接下来的指令中,可以通过this指针来访问对象的成员变量。

  400968:	48 8b 45 f8          	mov    -0x8(%rbp),%rax

使用mov指令将-0x8(%rbp)中存储的this指针加载到%rax寄存器中,用于后续指令对对象的操作。

  40096c:	8b 50 08             	mov    0x8(%rax),%edx

使用mov指令和偏移量0x8,从%rax寄存器指向的对象的地址中获取m_name成员变量的地址,并将其加载到%edx寄存器中。注意,由于m_name是一个字符串类型的成员变量,因此其地址也是字符串的地址,可以直接用于后续printf函数的调用。

  40096f:	48 8b 45 f8          	mov    -0x8(%rbp),%rax

再次使用mov指令将-0x8(%rbp)中存储的this指针加载到%rax寄存器中,用于后续指令对对象的操作。

  400973:	48 8b 00             	mov    (%rax),%rax

通过%rax寄存器访问对象的虚函数表指针(vptr),并将其加载到%rax寄存器中。

  400976:	48 89 c6             	mov    %rax,%rsi

使用mov指令将%rax寄存器中的值(即指向虚函数表的指针)复制到%rsi寄存器中,为后续printf函数的调用做准备。

  400979:	bf 50 0a 40 00       	mov    $0x400a50,%edi

三、new的源码

1、windows

C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.35.32215\crt\src\vcruntime

//
// new_scalar.cpp
//
//      Copyright (c) Microsoft Corporation. All rights reserved.
//
// Defines the scalar operator new.
//
#include <stdlib.h>
#include <vcruntime_new.h>
#include <vcstartup_internal.h>

// Enable the compiler to elide null checks during LTCG
#pragma comment(linker, "/ThrowingNew")


// new() Fallback Ordering
//
// +----------+
// |new_scalar<---------------+
// +----^-----+               |
//      |                     |
// +----+-------------+  +----+----+
// |new_scalar_nothrow|  |new_array|
// +------------------+  +----^----+
//                            |
//               +------------+----+
//               |new_array_nothrow|
//               +-----------------+

_CRT_SECURITYCRITICAL_ATTRIBUTE
void* __CRTDECL operator new(size_t const size)
{
    for (;;)
    {
        if (void* const block = malloc(size))
        {
            return block;
        }

        if (_callnewh(size) == 0)
        {
            if (size == SIZE_MAX)
            {
                __scrt_throw_std_bad_array_new_length();
            }
            else
            {
                __scrt_throw_std_bad_alloc();
            }
        }

        // The new handler was successful; try to allocate again...
    }
}

参考
1、《程序员的自我修养链接装载与库》文章来源地址https://www.toymoban.com/news/detail-544967.html

到了这里,关于【编译、链接、装载十六】汇编与指针、汇编与new的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Go语言之流指针类型,new函数

    计算机中所有的数据都必须放在内存中,不同类型的数据占用的字节数不一样,例如 int 占用 4 个字节。为了正确地访问这些数据,必须为每个字节都编上号码,就像门牌号、身份证号一样,每个字节的编号是唯一的,根据编号可以准确地找到某个字节。 我们将内存中字节的

    2024年02月16日
    浏览(26)
  • 64位AT&T汇编语言学习第一课:汇编和链接

    源文件 exitTest.s 内容如下: 源文件里边放的就是源代码,而我这里源代码是使用汇编语言写的,都是一些人类都可以阅读的字符。之后需要经过汇编器的汇编,变成目标文件(里边存放的是机器语言)。我这里使用的汇编器是GAS汇编器,命令是 as ,命令格式是 as 源文件名

    2024年01月17日
    浏览(39)
  • 64位AT&T汇编语言as汇编ld链接,执行报错Segmentation fault

    absCallAndPrintAbsAsLd.s 里边的内容如下: as -g absCallAndPrintAbsAsLd.s -o absCallAndPrintAbsAsLd.o 进行汇编。 ld -g absCallAndPrintAbsAsLd.o -o absCallAndPrintAbsAsLd -lc -I /usr/lib64/ld-linux-x86-64.so.2 进行链接。 ./absCallAndPrintAbsAsLd 执行报错 Segmentation fault 。 我把 rsp 中的地址加上8之后,就不报错了,因为这

    2024年01月24日
    浏览(34)
  • ARM学习(25)链接装载高阶认识

    ARM学习(25)链接装载高阶认识 笔者先引入几个编译链接的例子来介绍一下: 声明无效:declared implicitly?,属于编译错误还是链接错误? 编译阶段的错误 ,属于编译错误,因为编译器发现这个函数没有声明,声明异常 标识符/符号找不到:xxxx is undefined? undefined xxxxx? 无法解

    2024年03月27日
    浏览(30)
  • C语言·编译和链接

            在ANSI C的任何一种实现中,存在两种不同的环境         第一种是翻译环境,在这个环境中源代码被转换成可执行的机器指令         第二种是运行环境,它用于实际执行代码         我们知道项目中的以.c或.h为后缀的文件计算机是不认识的、无法直

    2024年01月19日
    浏览(25)
  • 【C语言】编译和链接

    前言: 编译和链接是计算机程序开发中的两个重要步骤,用于将源代码转化为可执行的程序。 翻译环境: 是指在开发计算机程序时所使用的工具和设置的集合。它包括开发者用来编写、测试和调试代码的软件工具,,如文本编辑器、集成开发环境(IDE)、编译器、调试器等

    2024年02月06日
    浏览(28)
  • C语言——编译和链接

    (图片由AI生成) C语言是最受欢迎的编程语言之一,以其接近硬件的能力和高效性而闻名。理解C语言的编译和链接过程对于深入了解其运行原理至关重要。本文将详细介绍C语言的翻译环境和运行环境,重点关注编译和链接的各个阶段。 在C语言编程中,翻译环境和运行环境

    2024年01月17日
    浏览(31)
  • 编译和链接---C语言

    众所周知,C语言是一门高级的编程语言,是无法被计算机直接读懂的,C语言也不同于汇编PHP,无法直接翻译成机器语言,在学习的过程中,你是否好奇过我们所敲的C语言代码,是如何一步步翻译成机器语言的呢?今天这篇博客---编译和链接,就是要带领我们解决这样的问题

    2024年01月25日
    浏览(27)
  • C语言编译和链接

    翻译环境和运行环境 在ANSI C的任何一种实现中,存在两个不同的环境 .第一种是翻译环境,在这个环境中源代码被转换为可执行的机器指令 .第二种是执行环境,它用于实际执行代码 翻译环境是由编译和链接两个大过程组成,而编译又可以分解成:预处理(预编译)、编译和

    2024年01月19日
    浏览(33)
  • 【C语言】编译与链接

    前言 我们想一个问题,我们写的C语言代码都是文本信息,电脑能直接执行c语言代码吗?肯定不能啊,计算机能执行的是二进制指令,所以将C语言转化为二进制指令需要一段过程,这篇博客讲一下编译与链接,来一起探讨C语言是如何转化为二进制指令的。 个人主页:小张同

    2024年04月16日
    浏览(27)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包