16 位 x86 MS-DOS 实模式下的分段远指针分配
Segmented far pointer allocation in 16bit x86 MS-DOS real mode
我正在尝试用 C 编写实模式 MS-DOS 程序。使用一些关于游戏编程的旧书作为起点。
书中的源代码是为 Microsoft C 编写的,但我试图让它在 OpenWatcom v2 下编译。我很早就 运行 遇到了一个问题,当时我试图访问指向 VGA 视频内存开始的指针。
#include <stdio.h>
#include <dos.h>
void Set_Video_Mode(int mode) {
union REGS inregs, outregs;
inregs.h.ah = 0;
inregs.h.al = (unsigned char) mode;
int86(0x10, &inregs, &outregs);
}
int main(void)
{
Set_Video_Mode(0x13);
//the following line throws an error, without it the code compiles and runs
char far *video_buffer = (char far *)0xA0000000L;
while (!kbhit()) { };
Set_Video_Mode(0x03);
return 0;
}
抛出以下错误的是远指针赋值:
VGA.C(33): Error! E1077: Missing '}'
VGA.C(33): Warning! W107: Missing return value for function 'main'
VGA.C(36): Error! E1099: Statement must be inside function. Probable cause: missing {
有点莫名其妙,好像是宏定义出错了,或者什么的...
当我使用相同的编译器在远指针上尝试维基百科 article 中的代码时:
#include <stdio.h>
int main() {
char far *p = (char far *)0x55550005;
char far *q = (char far *)0x53332225;
*p = 80;
(*p)++;
printf("%d", *q);
return 0;
}
编译通过。
编译命令在这两种情况下都是wcl -bcl=dos source.c
。
所以我现在有点困惑,似乎无法查明问题所在。
我正要在随机的地方扔几个星号和括号,看看它是否粘在某个地方......
您的 OpenWatcom C 编译器似乎默认使用 C89。在 C89 中,变量声明必须位于块作用域的开头。在您的情况下,您的所有代码和数据都在函数范围内,因此必须在代码之前的 main
开头声明变量。
以这种方式移动变量声明应该与 C89 兼容:
int main(void)
{
char far *video_buffer = (char far *)0xA0000000L;
Set_Video_Mode(0x13);
while (!kbhit()) { };
Set_Video_Mode(0x03);
return 0;
}
如果按照您的建议使用 OpenWatcom 2.0,您应该能够通过将选项 -za99
添加到 wcl
选项来使用 C99 模式进行编译。在 C99 中,您可以将变量声明放在块作用域顶部以外的位置。
当编译为 C89 时,Watcom 扩展了 C89 以允许 C++ 风格的注释,就像 C99 支持它的方式一样。此行为似乎 documented 为:
The Open Watcom C/16 and C/32 compilers support an extension for comments. The symbol // can be used at any point in a physical source line (except inside a character constant or string literal). Any characters from the // to the end of the line are treated as comment characters. The comment is terminated by the end of the line.
我同意不允许使用 C++ 样式注释的评估,编译器会更好地说明真正的问题是什么。一开始我也被愚弄了,我并没有马上想到它被编译为 C89 代码。自从 //
被接受后,我就假设它一定是 C99。
我正在尝试用 C 编写实模式 MS-DOS 程序。使用一些关于游戏编程的旧书作为起点。 书中的源代码是为 Microsoft C 编写的,但我试图让它在 OpenWatcom v2 下编译。我很早就 运行 遇到了一个问题,当时我试图访问指向 VGA 视频内存开始的指针。
#include <stdio.h>
#include <dos.h>
void Set_Video_Mode(int mode) {
union REGS inregs, outregs;
inregs.h.ah = 0;
inregs.h.al = (unsigned char) mode;
int86(0x10, &inregs, &outregs);
}
int main(void)
{
Set_Video_Mode(0x13);
//the following line throws an error, without it the code compiles and runs
char far *video_buffer = (char far *)0xA0000000L;
while (!kbhit()) { };
Set_Video_Mode(0x03);
return 0;
}
抛出以下错误的是远指针赋值:
VGA.C(33): Error! E1077: Missing '}'
VGA.C(33): Warning! W107: Missing return value for function 'main'
VGA.C(36): Error! E1099: Statement must be inside function. Probable cause: missing {
有点莫名其妙,好像是宏定义出错了,或者什么的...
当我使用相同的编译器在远指针上尝试维基百科 article 中的代码时:
#include <stdio.h>
int main() {
char far *p = (char far *)0x55550005;
char far *q = (char far *)0x53332225;
*p = 80;
(*p)++;
printf("%d", *q);
return 0;
}
编译通过。
编译命令在这两种情况下都是wcl -bcl=dos source.c
。
所以我现在有点困惑,似乎无法查明问题所在。 我正要在随机的地方扔几个星号和括号,看看它是否粘在某个地方......
您的 OpenWatcom C 编译器似乎默认使用 C89。在 C89 中,变量声明必须位于块作用域的开头。在您的情况下,您的所有代码和数据都在函数范围内,因此必须在代码之前的 main
开头声明变量。
以这种方式移动变量声明应该与 C89 兼容:
int main(void)
{
char far *video_buffer = (char far *)0xA0000000L;
Set_Video_Mode(0x13);
while (!kbhit()) { };
Set_Video_Mode(0x03);
return 0;
}
如果按照您的建议使用 OpenWatcom 2.0,您应该能够通过将选项 -za99
添加到 wcl
选项来使用 C99 模式进行编译。在 C99 中,您可以将变量声明放在块作用域顶部以外的位置。
当编译为 C89 时,Watcom 扩展了 C89 以允许 C++ 风格的注释,就像 C99 支持它的方式一样。此行为似乎 documented 为:
The Open Watcom C/16 and C/32 compilers support an extension for comments. The symbol // can be used at any point in a physical source line (except inside a character constant or string literal). Any characters from the // to the end of the line are treated as comment characters. The comment is terminated by the end of the line.
我同意不允许使用 C++ 样式注释的评估,编译器会更好地说明真正的问题是什么。一开始我也被愚弄了,我并没有马上想到它被编译为 C89 代码。自从 //
被接受后,我就假设它一定是 C99。