languages
14 messages in this thread
Well, from my standpoint, there is little difference in the C vs ASM
development cycle except that C catches many errors at COMPILE time.
Parameter mismatchs, assignment errors, uninitialized variables and type
mismatches can all be caught before you go through any of the compile
steps.
SAS/C has CPR which is a good debugger for C. You can access both the C
and for people that really want it ASM/Mixed modes. There is also the
catch.o mechanism that will trap many errors and then take a snapshot that
allows you to traceback where the problem occured – no rebooting involved..
The more I hear about C, the better it seems to be – at least for
large jobs. But are you really saying that 'uninitialised variables
… can be caught before you go through any of the compile steps'. Is
the compiler so clever that it can follow the logic of a program well
enough to actually do this?
Whether this is what you meant or not, it seems that I'd better get
hold of a copy of SAS/C and have a good look at it. I have quite a
large project that seems to have ground to a halt, partly because I
hit a problem which took me months (and a bit of luck) to solve. If
I decide to switch to using C, I will need to be able to include the
bulk of the existing ASM code. Is it easy to do this and to call C
routines from ASM?
Well, not before the compile step, but certainly before you execute.
Here's a trivial example I just tried…
main()
{
int foo;
printf("%d\n", foo);
}
(the square brackets above are actually curly braces, but CIS helpfully
translates them for us).
Then I did…
5> make test
…..
Compiling test.c
printf("%d\n", foo);
test.c 7 Warning 94: uninitialized auto variable "foo"
As you can see, it caught the use of the variable before it was
initialized.
Larry,
Excuse me for barging in on this thread, but could you explain why the
compiler was complaining? Doesn't int foo initialize the variable? How are
you supposed to initialize foo properly?
Tim, the 'int foo;' line allocates memory for the variable, and may
even set it to a particular value, like 0, but it is not considered
to be initialized unless done so explicitly by the programmer. This
can be done on the same line, by using the form 'int foo = 0;', or
later in the program by using it in an asignment, like 'foo = x;' or
'foo = getc();', and so on.
Note that the compiler did not refuse to compile the code, but issued a
warning and then carried on. In other words, you can use the uninitialized
variable, if you are willing to put up with the warning at compile time.
There really is no good reason to do so, since it is a simple matter to
initialize it, and since there is no guarantee that another compiler on a
different machine will create the variable with the same contents.
Your comment that the auto-variable foo 'may even be set to a particular
value, like 0' is not quite correct… auto variables are (usually) created
on the stack and NOT initialized at all, the value in that variable could
change each time yuo call the routine, depending on what happened to be on
the stack at the time.
In other words, it is not at ALL safe to ignore such warnings. While
you might get away with it, it can be the source of a sleeping time-bomb
bug that will certainly one day go off.
Yup, tou're right.. forgot about auto variables being created on the stack.
Still, one never knows what it might contain, and thus the warning. A
warning rather than an error, because the variable might be set by means
unforseeable by the compiler.
Thanks for the clarification. Part of my continued confusion is a result
of treating the compiler as a black box for now, and until I master some of
the more basic concepts I no doubt will blunder about 🙂 Why are they
called "automatic" variables?
> Why are they called "automatic" variables
Possibly because they are "automatically" allocated upon entry to a
function, and "automatically" de-allocated upon function exit. Just a
guess, but a reasonable one 😎
Good guess…that's exactly why they're called 'automatic'
variables… they come into existance on entry to the function, and
disappear on exit from the function.
Tim,
auto variables whether created on the stack, or not, and are not
initialized, thus are whatever value happens to be at that point in memory
(or stack) until the program initializes it.
From K&R (2nd Edition):
In the absence of explicit initialization, external and
static variables are guaranteed to be initialized to zero; automatic
and register variables have undefined (i.e., garbage) initial values.
Just FYI — CIS converts braces to brackets only in CO — no
conversion is done with messages.
-sja- via AP 0.04A
Yes, the compiler can catch uninitialized variables within the scope
of a subroutine. It obviously can't follow all flows, but due to the
global analysis phase it can get quite close (using the REF/DEF
model). There are a few pathological cases that can skip by it (such
as conditional initialization of a variable) but in practice these
are so rare to not be an issue.
SAS/C has a concept that I introduced for the Amiga of __asm
specifications for routines. You can declare an external routine as
__asm and then give the register conventions for the calling
sequence. This combined with the registerized parameters in general
for code (using the -rr option on the compiler) can lead to some
quite good code. Also, the assembler will output line number
information that the debugger understands so that you can debug your
assembler code at the SOURCE level – a strange concept I might add.
>Is the compiler so clever that it can follow the logic of a program
>well enough to actually do this?
In enough cases: yes. First of all, all static variables become initialized
implicitly if you do not do so explicitely. Automatics without initializers
have undetermined values though. So, it becomes a quality of implementation
issue that it should diagnose twice something like:
void foo()
{
int i;
int j;
printf("%d\n", i); /* who know what prints out */
i = j; /* j used before set */
}
There are queasy cases though that are either too much work, or sometime
impossible to calculate. Consider:
main()
{
int i;
int j;
scanf("%d", &i);
if (i)
j = i;
/* j is either i here, OR who know what */
}
Not that a compiler can't do flow analysis and conclude anything, but
that case does before iff'y er since something like "j might not be
set" starts getting inconclusive (unless addition info can be
provided).