我正试着用C语言编写实模式MS-DOS.以一些关于游戏编程的旧书为起点.

#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 {

这有点让人困惑,似乎宏观定义出了问题,或者其他什么...

当我使用相同的编译器在远指针上try Wikipedia 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;
}

它编译.

所以我现在有点不知所措,似乎无法确定问题所在.

推荐答案

您的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,因为:

Open Watcom C/16和C/32编译器支持注释扩展.符号//可以在物理源行中的任何点使用(字符常量或字符串文本内部除外).从//到行尾的任何字符都被视为注释字符.注释在行尾结束.

我同意,C++语言注释不被允许的判断,编译器会更好地了解实际问题.一开始我也被愚弄了,我没有马上想到它被编译成了C89代码.自从//被接受以来,我一直认为它一定是C99.

C++相关问答推荐

如何将不同长度的位转换成字节数组?

无法用C++编译我的单元测试

限制不同类型的限定符

X64:并发写入布尔数组

在每种If-Else情况下执行语句的最佳方式

S的这种管道实施有什么问题吗?

从TCP连接启动UDP(C套接字)

GCC奇怪的行为,有fork 和印花,有换行符和不换行符

指向不同类型的指针是否与公共初始序列规则匹配?

-Wnonnull-Compare警告不是具有误导性吗?

C代码可以在在线编译器上运行,但不能在Leetcode上运行

GCC错误,共享内存未定义引用?

为什么电路板被循环删除?

链接器脚本和C程序使用相同的头文件,这可能吗?

为什么我的半数组测试和奇数组测试不起作用?(我使用Assert进行调试)

哪些C++功能可以在外部C块中使用

如何不断地用C读取文件?

如何使crc32的结果与cksum匹配?

括号中的 C 函数声明显然永远调用自身,有什么意义?

在内存泄漏中获取Syscall param execve(argv) 指向未初始化的字节?