Giter Site home page Giter Site logo

请教一个问题 about justatoyccompiler HOT 5 CLOSED

tch0 avatar tch0 commented on June 18, 2024
请教一个问题

from justatoyccompiler.

Comments (5)

tch0 avatar tch0 commented on June 18, 2024

首先因为支持32位和64位,在64位时定义了#define int int64_t,也就是说无论Windows还是Unix其实int和指针都是一个大小,32位环境中就是32位,64位环境中就是64位。和标准其实并不一样,只是为了实现方便。

然后,因为在基础版本jatcc.c中只支持char、enum、int以及他们的指针类型,而enum简单等同于int,指针和int大小相同都是sizeof(int)。考虑表达式++x:现在只有两种情况,x是char、enum、int、char*就加1,也就是sizeof(char),而x是int*, char**, int***之类非char*的指针类型都是加sizeof(int)。因为CHAR值为0,而指针复合类型就是在基础类型之上每一层指针加上一个PTR,所以char *的类型就等于PTR,所以条件是>PTR。这里确实会比较令人费解。

简单来说这是因为只支持了这几个类型才可以这样做,在支持了union和struct之后就不能这样了,就需要取他们的单元的大小,见https://github.com/tch0/JustAToyCCompiler/blob/master/jatccex.c#L917

具体的汇编就比较简单了,可以自己分析。

from justatoyccompiler.

BridanLSP avatar BridanLSP commented on June 18, 2024

谢谢,x是char、enum、int、char*就加1因为CHAR值为0,而指针复合类型就是在基础类型之上每一层指针加上一个PTR,所以char *的类型就等于PTR,所以条件是>PTR。我已经理解了。

但还是有点问题。对于 int *x 而言,++x 即取 x 指针紧接着的下一个指针,那它不同样是加一吗?为什么要加 sizeof(int)?而且在c语言中,+sizeof(int)也不能正常工作。我是不是遗漏了什么?

#include <stdio.h>
#include <stdlib.h>
int main() {
    int *x, *y;
    x = malloc(1024);
    y = x;
    *x = 1;
    *++x = 2;
    *++x = 3;
    *++x = 4;
    *++x = 5;
    *++x = 6;
    *++x = 7;
    *++x = 8;

    printf("%d %d", *y, *(y+sizeof(int)));
    // 输出:1 5
}

from justatoyccompiler.

tch0 avatar tch0 commented on June 18, 2024

你可能没有绕过这个弯来,指针中保存的是地址,对于int* x++x是移动到到下一个指针,那么指针的值(就是那个地址)就是加了sizeof(int),C语言提供了这个机制,而现在是由我们来实现这个机制。如果是x+sizeof(int),那不是移动到下一个元素,而是移动到后面第sizeof(int)个元素,它的值(地址)是x的值加上sizeof(int)*sizeof(int)

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int x[10];
    printf("%p %p\n", x, x+1);
    return 0;
}

示例输出:

0x7ffdfdf93440 0x7ffdfdf93444

from justatoyccompiler.

tch0 avatar tch0 commented on June 18, 2024

说得更清楚一点,无论什么指令集体系结构,在汇编、机器码这个层面,都是没有类型的概念的(这里的极简指令集同样),有的只有操作1字节、2字节、四字节、八字节、字、双字、四字等大小的指令,对于机器来说,没有任何手段来区分一个地址或者一个整数。C语言中指针的算术运算和算术类型不一样,指针的运算需要乘以基础类型大小,这是C语言提供的语法糖,也是需要编译器来做的事情,我们正是在做这个事情。

比如x86-64架构:

int* test(int* p)
{
    return p + 1;
}

汇编:

test:
.LFB12:
	.cfi_startproc
	leaq	4(%rdi), %rax
	ret

leaq 4(%rdi), %rax就是对传入的值加4,然后作为返回值。在这个上下文中你无法判断这到底是一个整数还是一个指针。
你如果编一下下面这个函数,你会发现他们的汇编是完全相同的(在64位下):

int64_t test(int64_t x)
{
    return x + 4;
}

from justatoyccompiler.

BridanLSP avatar BridanLSP commented on June 18, 2024

我明白了,加一只会让指针到下一个字节,而不是下一个整数。谢谢兄弟,祝你新年快乐!

from justatoyccompiler.

Related Issues (2)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.