在c(操作系统开发)中,对字符串进行迭代会返回空



我正在制作操作系统,或者至少在尝试,但我偶然发现了一个问题。当试图迭代字符串以转换为char打印到屏幕时,返回的char似乎是空的!(实际上我是操作系统开发的新手(;以下是代码片段:

int offset = 0;
void clear_screen() {
unsigned char * video = 0xB8000;
for(int i = 0; i < 2000; i+=2){
video[i] = ' ';
}
}
void printc(char c) {
unsigned char * video = 0xB8000;
video[offset] = c;
video[offset+1] = 0x03;
offset += 2;
}
void print(unsigned char *string) {
char * sus = '';
uint32 i = 0;
printc('|');
sus[0] = 'a';
printc(sus[0]);  //this prints "a" correctly
string[i] = 'c';
while (string[i] != '') {
printc(string[i]);   //this while loop is only called once 
i++;                 //it prints " " only once and exits
}
printc('|');
}
int bootup(void)
{
clear_screen();
// printc('h');
// printc('e');
// printc('l');                     /* These work */
// printc('l');
// printc('o');
print("hello"); //this doesn't
return 1;
}

它打印的输出:

|a |

提前感谢!!

编辑

新的打印功能

void print(unsigned char *string) {
uint32 i = 0;
printc('|');
while (string[i] != '') {
printc('i');  //not printed
printc(string[i]);
i++;
}
printc('|');
}

仍然不起作用

编辑2根据@lundin的建议更新了代码

int offset = 0;
void clear_screen() {
unsigned char * video = (unsigned char *)0xB8000;
for(int i = 0; i < 2000; i+=2){
video[i] = ' ';
}
}
void printc(char c) {
unsigned char * video = (unsigned char *)0xB8000;
video[offset] = c;
video[offset+1] = 0x03;
offset += 2;
}
void print(const char *string) {
int i = 0;
printc('|');
while (string[i] != '') {
printc('i');
printc(string[i]);
i++;
}
printc('|');
}
int bootup(void)
{
clear_screen();
// printc('h');
// printc('e');
// printc('l');
// printc('l');
// printc('o');
print("hello");
return 1;
}

堆栈:

init_lm:
mov ax, 0x10
mov fs, ax          ;other segments are ignored
mov gs, ax
mov rbp, 0x90000    ;set up stack
mov rsp, rbp
;Load kernel from disk
xor ebx, ebx        ;upper 2 bytes above bh in ebx is for cylinder = 0x0
mov bl, 0x2         ;read from 2nd sectors
mov bh, 0x0         ;head
mov ch, 1           ;read 1 sector
mov rdi, KERNEL_ADDRESS
call ata_chs_read

jmp KERNEL_ADDRESS
jmp $

在继续之前,我建议阅读基于文本的UI上的OSDev wiki页面。

虽然这可能在一定程度上超出了问题的范围,但我强烈建议您不要手动将字符/属性值作为unsigned char来处理,而应该为这些对声明一个struct类型:

struct TextCell {
volatile unsigned char ch;
volatile uint8_t attribute;
};

(实际上,通过为属性的各个前景、背景和装饰组件使用位字段,您可以对其进行更精细的处理,但这可能会超前。(

从那里你可以将文本缓冲区定义为一个常量指针:

const struct TextCell* text_buffer = (TextCell *)0xB8000;

您可以进一步定义

const uint16_t MAXH = 80, MAXV = 25;
uint16_t currv = 0, currh = 0;
struct TextCell* text_cursor = text_buffer;

void advance_cursor() {
text_cursor++;
if (currh < MAXH) {
currh++;
}
else {
currh = 0;
if (currv < MAXV) {
currv++;
}
else {
/* handle scrolling */
}
}
}
void gotoxy(uint16_t x, uint16_t y) {
uint16_t new_pos = x * y;
if (new_pos > (MAXV * MAXH)) {
text_cursor = text_buffer + (MAXV * MAXH);
currh = MAXH;
currv = MAXV;
}
else {
text_cursor += new_pos;
currh = x;
currv = y;
}

这将导致对您的代码进行以下修改:

void kprintc(char c, uint8_t attrib) {
text_cursor->ch = c;
text_cursor->attribute = attrib;
advance_cursor();
}
void kprint(const char *string, uint8_t attribs) {
int i;
for (i = 0; string[i] != ''; i++) {
kprintc(string[i], attribs);
}
}
void clear_screen() {
for(int i = 0; i < (MAXH * MAXV); i++) {
kprintc(' ', 0);
}
}
int bootup(void) {
clear_screen();
// kprintc('h', 0x03);
// kprintc('e', 0x03);
// kprintc('l', 0x03);
// kprintc('l', 0x03);
// kprintc('o', 0x03);
kprint("hello", 0x03);
return 1;
}

那么,我为什么要建议所有这些额外的东西呢?因为用这种方式调试要容易得多,主要是因为它能更好地划分问题,更有效地构建数据(或者在这种情况下,视频文本缓冲区(。此外,在项目中的某个时刻,您最终需要做这样的事情,所以如果这对现在有帮助,您还不如现在就做。

如果我在这件事上越界了,请告诉我。

您的程序有未定义的行为,因为它包含多行无效的C。您将收到关于这些行的编译器消息。

  • unsigned char * video = 0xB8000;等不是有效的C,您需要显式强制转换"来自整数的指针/来自不带强制转换的指针的整数";问题
  • 类似地,char * sus = '';也是无效的C。您试图将指针分配给单个字符,这是没有意义的。字符串处理初学者常见问题解答:C编程中常见的字符串处理陷阱。它还解决了内存分配的基本问题
  • sus[0] = 'a';等等,因为sus没有指向有效内存,所以这里有大量未定义的行为
  • 如果你真的试图访问物理内存地址,这不是正确的方法。你需要volatile限定指针。请参阅如何从固件访问硬件寄存器?(在您的情况下,它可能不是一个寄存器,但该链接中的所有内容仍然适用——如何使用十六进制常量等。(
  • 编辑:void print(unsigned char *string)。。。string[i] = 'c';也是错误的。首先,您传递的是一个char*,它不一定与unsigned char*兼容。那么,您不应该从一个名为print的函数内部修改传递的字符串,这是没有意义的。这应该是const char* string以防止此类错误。目前,您正在向该函数传递一个字符串文字,然后尝试修改它——这是未定义的行为,因为字符串文字是只读的

假设是gcc或clang,如果您希望阻止编译器用无效的C代码生成可执行文件,请查看学习C的初学者建议使用哪些编译器选项?在您的情况下,您可能还需要上面提到的-ffreestanding选项。

char * sus = '';

尚未检查更多。。。但这会为sus分配一个空指针,很可能不是您想要做的

最新更新