************************************************************************ * Jouni Miettunen * jon@stekt.oulu.fi * Oulu * Finland * Europe * 1995 * Intermediate Programmer Tutorial #002 Copyright (c) 1995 by Jouni Miettunen Version 1.2 - 12 June 1995 Turbo C++ 3.0 Bugs and How to Deal with Them ** INTRODUCTION I code small DOS applications, usually with my own GUI library. None of the programs need to be realtime, handle multiple huge datafiles or do several things at the same time. Still they need to function correctly. The purpose of this tutorial is to collect information about TC3 bugs, peculiar or annoying features and how to cope with them. If you have some more information, please contact me and I'll update this document. I have already released one buggy program, when I couldn't make the final "clean" compilation thanx to constant compiler crashes. I'm sure the tone of this document will reveal you what I think about such a product and a company. ** THE GOOD, THE BAD AND TURBO C++ 3.0 My Chosen Compiler (TM) is TC3 and I am not too happy with it. When I have afford, I'll buy Watcom C/C++ compiler.. in case I'll continue writing DOS programs. The bad points are that Borland doesn't support TC3 anymore and that it is buggy. On the other hand this is quite understandable remembering it was released 1992 and is a DOS program. The manual isn't quite adequate even as an elbow rest and the online Reference Guide doesn't fill my needs. The good points are that it was reasonably inexpensive, is reasonably fast, generates reasonably tight code and usually works just fine. The most important feature is IDE (Integrated Development Environment ie. a Text User Interface) to help developing, debugging, compiling and linking programs in the same nice visual environment. Code hilighting is a feature I've found very useful. You also has to remember that TC3 is an ANSI C compiler, supports the basic features of C++ and comes with a royalty free full graphics library (BGI). The money I spent buying it was not wasted, I just thought I'd get a perfect program. Instead I got a rude awakening.. ** WINERROR 3 TC3 supports several screen resolutions (24/43/50 lines) and thus has some internal information about the locations of its windows. Sometimes this info gets corrupted and fools TC3 to try to open windows or dialogs outside the visible screen area. The result is compiler crash. If you get lucky, only the compiler will crash (winerror = 3) and you can try again, but occasionally also the whole system crashes needing a reboot. The solution is to every now and then close all open windows and reopen those you need. This is done by selecting Window menu and there item Close All. Another possibility is to delete the desktop file (*.dsk) before starting TC3. Window:Close All - just select this once ** NOT ENOUGH MEMORY TO START If you use IDE, but don't have enough memory to load datafiles or even start the program, disable Debugger. Also remember to disable the two related debugging options. Options:Compiler:Advanced Code Generation:Line Numbers Debug Info - OFF Options:Compiler:Advanced Code Generation:Debug Info In OBJs - OFF Options:Debugger:Source Debugging - OFF ** NOT ENOUGH MEMORY TO DEBUG Sometimes you would like to debug your program with the build-in debugger, but can't, since there's not enough free memory.. or that's what TC3 thinks. By default only 64K is reserved for your program's dynamically allocated data. Fortunately you can increase this value by yourself and debug the program just fine. Still you have to remember that there is a real limit in the amount of available memory that can't be changed by any compiler options. Options:Debugger:Program Heap Size - write a new value I'd recommend using values under 640K, the amount of conventional DOS memory. If you need more, don't use TC3. ** BUILT-IN ASSEMBLER Turbo C comes with a built-in assembler. The manual index says to see "The online document" mentioning filename UTIL.DOC, but the correct file is BASM.DOC. There are few things to remember about BASM syntax: labels have to be outside asm {} block and the comments have to be C or C++ comments. SkipScanLine: waitHRTend: asm { in al,dx test al,01h jz waitHRTend } waitHRTstart: asm { in al,dx test al,01h jnz waitHRTstart loop short SkipScanLine /* wait till cx scan lines passed */ } The inline assembler is a 16-bit assembler and supports only 8086 code generation. However placing the 66h "operand size override" on the line before the instruction can force it to be understood as 32-bit. asm db 0x66 asm rep stosw // rep stosd ** 64K LIMIT The most frustrating thing in DOS programming is the memory management and especially the long and hard cursed 64k limitation in.. everything! If you read a file into a buffer, you can read only the first 64k. If you print a text string, you can print only the first 64k. The solution seems to be using huge pointers, as suggested in various referencies. The problem is that huge pointers are really slow.. but the problem might be the solution, if you know what you're doing: using huge pointers mean in practice that you use far pointers that are normalized everytime their value is changed. You can do this yourself, if you can identify the moments, when it is necessary. ** INCREMENTING POINTERS There is something strange in the pointer incrementation.. According to the ANSI C specification, which TC3 is supposed to obey, the following code examples should do exactly the same thing: add 2 into the value of the variable. char far *ch; ch += 2; ch = ch + 2; However TC3 generates different code for them: ; ; ch += 2; ; add word ptr [bp-4],2 ; ; ch = ch + 2; ; mov ax,word ptr [bp-2] mov dx,word ptr [bp-4] add dx,2 mov word ptr [bp-2],ax mov word ptr [bp-4],dx At first sight this might seem ok: both add the requested value into the offset of the variable (and offset wraps around). The first example even might seem to be a better choice, since it generates less "unused" code. However in practise I've found the second way to be more reliable.. Occasionally the first one just doesn't seem to be doing what the code says it to do, especially when incrementing char far *pointers. Since I don't have any real asm manual, I can't tell at the moment what is the difference in operation. First one is an indirect addition and the second one is a direct addition with a register. Should RTFM a bit.. ** HISTORY 1.0 Winerror 3, Not enough memory to start 1.1 BASM, Pointer normalization 1.2 Not enough memory to debug, Pointer incrementation ** DISCLAIMER Please note I have written this tutorial in good faith, but I cannot guarantees its contents. I think it's all correct, that things really work this way and could be taken care of like this. If something goes wrong, that will be your problem, not mine. You have been warned. Additions, fixes and spelling and grammar instructions are most welcome. Hope you could find this useful. This tutorial is copyrighted, but freely redistributable material. ** AUTHOR Mr. Jouni Miettunen Rautatienkatu 20 A 10 FIN-90100 OULU FINLAND - EUROPE * Jouni Miettunen * jon@stekt.oulu.fi * Oulu * Finland * Europe * 1995 * ************************************************************************