【问题标题】:Writing to video memory (0xB8000) & volatile pointer写入显存 (0xB8000) 和易失性指针
【发布时间】:2015-08-26 08:35:30
【问题描述】:

我正在尝试用 C 编写自己的小内核,实际上我想编写一个打印函数来显示字符串。因此,我想写入视频内存(0xB8000)。

所以,我是这样尝试的:

unsigned char *video = (unsigned char *)0xB8000;

*video = 'A';

这确实有效,但以下无效:

char x = 0;
unsigned char *video = (unsigned char *)(0xB8000 + x);

*video = 'A';

经过一番研究,我认为原因可能是编译器的优化,OSDev 给了我解决方案:使用volatile 关键字。所以我对这个关键字做了一些研究。 OSDev 建议这样做:

char x = 0;
volatile unsigned char *video = (volatile unsigned char *)(0xB8000 + x);

*video = 'A';

这样,它应该可以工作。编译器假定video 指针指向的值可以改变,然后不对其进行优化。但是,如果以后我想更改它,例如:

video = (volatile unsigned char *)(video + 2);

我不应该将指针定义为volatile,比如unsigned char * volatile video吗?那么编译器知道地址可以改变吗?

【问题讨论】:

  • 我不明白没有 volatile 什么是行不通的? unsigned char *video = (unsigned char *)(0xB8000 + x);。我想问题是xchar 而不是int/unsigned。类型可能是问题,而不是非波动性
  • @i486 如果编译器能够推断出video 的内容永远不会被读取,它可能会优化对它的写入。
  • 为什么(unsigned char *)(0xB8000 + x) 不会将值写入视频内存而(unsigned char *)0xB8000 会这样做?我认为不可能有这样的优化。只有video 的值可以保存在 CPU 寄存器中,而不是它的内存位置。
  • 我同意这很奇怪,但是在第一种情况下不会发生优化这一事实并不是真的不会在第二种情况下发生的论点案例。
  • 请注意,虽然在这里使用volatile(可能)是有效的,但在将它用于整个内核之前,您应该阅读this。一个更好的方法,而不是声明videovolatile,是将所有需要可变的访问转换为volatile

标签: c pointers memory volatile


【解决方案1】:

volatile 的意义在于告诉编译器变量的内容可能会在您的代码执行之外发生变化或产生副作用。正如standard (C99 6.7.3.6) 所说:

具有 volatile 限定类型的对象可能会以实现未知的方式被修改或具有其他未知的副作用。因此,任何引用此类对象的表达式都应严格按照抽象机的规则进行评估,如 5.1.2.3 中所述。此外,在每个序列点,最后存储在对象中的值应与抽象机规定的值一致,除非由前面提到的未知因素修改。构成对具有 volatile 限定类型的对象的访问是由实现定义的。

这就是为什么你需要告诉编译器变量指向的内存是易失的。但是,更改指针指向的地址不会导致任何副作用,并且不会在代码执行之外自行更改,因此指针本身没有理由变为易失性。如果我们必须将我们希望在某个时刻更改的所有变量都标记为volatile,那么几乎所有变量都必须这样标记。

【讨论】:

    【解决方案2】:

    为什么不:

    unsigned char * video = 0xB8000;
    video[x] = 'A';
    

    【讨论】:

    • 当然,这是可能的,也许是最好的方法,但它并没有向我解释我的 volatile 问题背后的原因;)
    • 这不起作用。编译器可能会将其优化掉。并且转换地址文字更好
    猜你喜欢
    • 2020-02-26
    • 2018-01-26
    • 1970-01-01
    • 1970-01-01
    • 2016-04-04
    • 2015-04-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多