Think C 5.0
Volume Number: 7
Issue Number: 9
Column Tag: Tools of the Trade
THINK C 5.0 
By Chris Faigle, Richmond, VA
Think C 5.0 is here! This new version of Symantec’s compiler and environment
has an incredible number of new features. I have had a few months to use it (since I
was a beta tester), and I feel it is so far superior to 4.0, that they are not in the same
class. This article is too short to describe all of the new features, but I will try to hit
all of the major changes, and a lot of the minor ones. Just to whet you appetite, I’ll
mention a few now: Completely rewritten compiler, new disassembler, new code
optimizer, new preprocessor, fuller object implementation, class browser, and
supports MPW header files!
The Compiler
The compiler has been completely rewritten. The folks at Symantec decided that
in order to support all of the features that they wanted, they needed to almost start
over. This cost them a lot of time and effort, but the results were worth it: A C
compiler so flexible, that it can become ANSI conformant, down to even recognizing
trigraphs, or change to accept Objects and Think C Extensions, use the native 68000
floating point structure, change how it decides a function’s prototype, generate
MacsBugs labels in both short and long format, and even run a global Optimizer over the
code. I will try to elaborate briefly on all of these areas and more.
Figure 1: Options Dialog (Language Settings Shown)
Compiler Options
The Options dialog (Figure 1) is your main control over the compiler. It has
now been expanded to have six areas of options: Preferences, Language Settings,
Compiler Settings, Code Optimization, Debugging and Prefix. Each option, when selected
will bring up a help message in the dialog. The Factory Settings button will change the
settings in each area, not just the area that you are in, to the settings that THINK C
comes with. All of the settings are saved in the project, and you can also change the
settings that Think C will open a new project with. Further, most of the options can
also be changed by using #pragma options preprocessor directive in your source. Two
other options for applications are located in the Set Project Type dialog, and they are
Far Code: jump tables (but not segments) >32k and Far Data: global data up to 256k.
File: 0 “Hello World.c”
File: 1 “MacTraps”
File: 2 “ANSI”
Segment “%GlobalData” size=$000622
_abnormal_exit -$000610(A5) file=”ANSI”
__console_options -$000536(A5)
__log_stdout -$0004E2(A5)
__ctype -$000424(A5)
errno -$000324(A5)
_ftype -$0002F0(A5)
_fcreator -$0002EC(A5)
__file -$0002E8(A5)
__copyright -$00003A(A5)
Segment “Seg2” size=$000010 rsrcid=2
main $000004 JT=$000072(A5) file=”Hello World.c”
Segment “Seg3” size=$00479A rsrcid=3
malloc $000004 file=”ANSI”
calloc $000040
realloc $0000C0
free $0001C6
atexit $000290
etc
Figure 2: Link Map (Abbreviated)
Language Settings
Three main areas occupy the language settings (Figure 1). The ANSI
conformance section has options that when on are ANSI conformant. These are things
like #define _STDC_. The easiest way to provide complete ANSI conformance is to click
the ANSI Conformance button that is added to the dialog, however, you must read this
section of the manual. You can get burned if you do not understand all of the
ramifications of being totally ANSI conformant. For example, if you are completely
ANSI conformant, the compiler will think ‘????’ is a trigraph and not a long (as used
in File and Creator types).
The Language extensions section allows you to choose to support the ThinkC
extensions (like asm{}, pascal keyword, and // comments), ThinkC and Object
extensions, or no extensions. The prototype section selects whether Think C strictly
enforces prototypes, and if it does, whether it requires an explicit prototype, or
whether it will infer what the prototypes is from either the function, or a call to that
function, whichever comes first.
Compiler Settings
This area let’s you change some of the ways that Think C generates code, like
whether to generate 68020 & 68881 instructions, instead of plain 68000. It also lets
you change several of the default characteristics of Think’s Objects. In addition, it will
let you use ‘Native Floating Point’ format. The manual has a long discussion of all of
the ramifications of this, but suffice it to say that floating point calls are faster with
this option on (1:10 vs 1:14 for 32000 sin’s & no SANE), but the ANSI library (and
any that you have that use floating point variables) must be recompiled with this option
on, and you should probably not distribute libraries with this feature on, unless the
recipient is also going to use it.
Think C now provides six different types of optimization that the user can select.
You can use all of them, or choose only the ones you want, plus automatic register
assignment. Unfortunately, almost all can interfere to some extent with the Source
Debugger, since they change calls and variables, and can make the code look somewhat
different than what the Debugger expects. I have not really had any serious problems
when source debugging, but it is generally a good idea to save the optimization for your
builds.
Defer and Combine Stack Adjusts (Figure 3) accumulates adjustments to the
stack until they are necessary. In the example, without DCSA on, two stack
modifications are made [ADDQ.L #$2,A7], but with it on, they are removed. The
compiler is even smart enough to recognize that instead of accumulating them into
[ADDQ.L #$4,A7] they can be removed altogether, since [UNLK A6] is the next
instruction!
Supress Redundant Loads (Figure 4) will not load variables into registers if they
are already in a register. Furthermore, it will also perform moves from registers
[0014MOVE.W D0,$FFFA(A6)] rather than from memory [0014 MOVE.W
$FFFC(A6),$FFFA(A6)] if the variable is already in a register. This instruction is
faster to both load (2 less bytes) and faster to execute.
Induction Variable Elimination will optimize loops that access arrays by
remembering the address of the last accessed element of the array and adding the size of
the element to access the next one, rather than making the Mac perform 32-bit
multiplication every time. An example of the code that would be optimized by this is:
/* 1 */
Example source code:
main()
{
short x;
short y;
func1(x);
func2(y);
}
Defer and Combine Stack Adjusts OFF:
main:
00000000 LINK A6,#$FFFC
00000004 MOVE.W $FFFE(A6),-(A7)
00000008 JSR $0000(A5)
0000000C ADDQ.L #$2,A7
0000000E MOVE.W $FFFC(A6),-(A7)
00000012 JSR $0000(A5)
00000016 ADDQ.L #$2,A7
00000018 UNLK A6
0000001A RTS