R
Ross A. Finlayson
Hi,
I hope you can help me understand the varargs facility.
Say I am programming in ISO C including stdarg.h and I declare a
function as so:
void log_printf(const char* logfilename, const char* formatter, ...);
Then, I want to call it as so:
int i = 1;
const char* s = "string";
log_printf("logfile.txt", "Int: %d String %s", i, s);
Then, in the definition of log_printf I have something along the lines
of this:
void log_printf(const char* logfilename, const char* formatter, ...){
va_list ap;
FILE* logfile;
if(logfilename == NULL) { return; }
if(formatter == NULL) { return; }
logfile = fopen(logfilename, "a");
if( logfile == NULL ) { return; }
va_start(ap, formatter);
fprintf(logfile, formatter, ap );
va_end(ap);
fprintf(logfile, "\n");
fclose(logfile);
return;
}
As you can see I want to call fprintf with its variable argument list
that is the same list of arguments as passed to log_printf.
Please explain the (a) correct implementation of this function. I
looked to the C Reference Manual and Schildt's handy C/C++ Programmer's
Reference and various platform's man pages and documentation with
regards to this, and don't quite get it. I search for va_start(ap,
fmt).
Then, also I have some questions about shift on little-endian
processors. As an obligatory topicality justification, performance
issues of C are on-topic on comp.lang.c. Anyways, in the HLL C when
you shift the 32 bit unsigned value 0x00010000 one bit right the result
is equal to 0x00008000. Now, on little-endian architectures that is
represented in memory as
00 00 01 00
and then
00 80 00 00
On the LE register as well, its representation is
00 00 01 00
and then shifting it one bit right in the HLL leads to
00 80 00 00
but one would hope that the shr for shift right instruction would
instead leave:
00 00 00 80
so I am wondering if besides using assembler instructions there are
other well known methods in the high level language for shifting,
particularly in terms of one bit shift and multiples of eight bit
shifts.
That's basically about the conflict between msb->lsb bit fill order but
LSB->MSB, LE or Little-Endian byte order, and correspondingly between
lsb->msb and MSB->LSB, BE or Big-Endian, in terms of high level shift
and instruction level shift. I have not decompiled the output of the
compiler on the LE machine, maybe that would be the most direct way to
see what the compiler does to accomplish bit shifts across byte
boundaries that preserve numeric values, but if you happen to know
offhand, that would be interesting and appreciated. I'm basically
looking at the basic necessity of assembler for a bit scanner. It is
acceptably easily done in the HLL, I'm just concerned about trivial
issues of compiler instruction generation.
Here's another question, but it's about the linker. Say, a unit
contains multiple symbols, that have by default the extern storage
class. I guess it's up to the linker to either draw in all symbols of
the module or pull the used symbols out of the compiled module. I look
at the output with gcc, and it draws in symbols that are unused, just
because some other symbol in the same compilation unit is used. for
example:
[space:~/Desktop/fc_test] nm Build/test
....
00003c7c T _fc_mem_free
00003c38 T _fc_mem_malloc
00003cc4 T _fc_mem_realloc
00003d10 T _fc_mem_stackalloc
00003d6c T _fc_mem_stackfree
....
All of those definitions are in the same compilation or translation
unit, but only fc_mem_stackalloc and fc_mem_stackfree are actually
used, and there is no reason for that code to be in the output. I
change the optimization to -O3 and the unnecessary symbols are still
there.
[space:~/Desktop/fc_test] space% cc -v
Reading specs from /usr/libexec/gcc/darwin/ppc/2.95.2/specs
Apple Computer, Inc. version gcc-926, based on gcc version 2.95.2
19991024 (release)
It's one consideration to divide the compilation units so that each
compilation unit contains only one function, but that gets very bulky,
as some of the translation units in this project have dozens of nearly
identical functions, and I would rather not have hundreds of source
code files if I could hint to the linker to remove unnecessary code.
Some programs linking to the static library only need one of those
hundreds of generated functions.
So:
1. variadic function arguments going to called variadic function?
2. HLL shift on Little-Endian?
3. linker hints for unneeded symbols besides compiling into separate
units
Then I have some questions about best practices with signals, Microsoft
SEH or Structured Exception Handling, portability and runtime
dependency of longjmp, and stuff.
Thank you!
Ross F.
I hope you can help me understand the varargs facility.
Say I am programming in ISO C including stdarg.h and I declare a
function as so:
void log_printf(const char* logfilename, const char* formatter, ...);
Then, I want to call it as so:
int i = 1;
const char* s = "string";
log_printf("logfile.txt", "Int: %d String %s", i, s);
Then, in the definition of log_printf I have something along the lines
of this:
void log_printf(const char* logfilename, const char* formatter, ...){
va_list ap;
FILE* logfile;
if(logfilename == NULL) { return; }
if(formatter == NULL) { return; }
logfile = fopen(logfilename, "a");
if( logfile == NULL ) { return; }
va_start(ap, formatter);
fprintf(logfile, formatter, ap );
va_end(ap);
fprintf(logfile, "\n");
fclose(logfile);
return;
}
As you can see I want to call fprintf with its variable argument list
that is the same list of arguments as passed to log_printf.
Please explain the (a) correct implementation of this function. I
looked to the C Reference Manual and Schildt's handy C/C++ Programmer's
Reference and various platform's man pages and documentation with
regards to this, and don't quite get it. I search for va_start(ap,
fmt).
Then, also I have some questions about shift on little-endian
processors. As an obligatory topicality justification, performance
issues of C are on-topic on comp.lang.c. Anyways, in the HLL C when
you shift the 32 bit unsigned value 0x00010000 one bit right the result
is equal to 0x00008000. Now, on little-endian architectures that is
represented in memory as
00 00 01 00
and then
00 80 00 00
On the LE register as well, its representation is
00 00 01 00
and then shifting it one bit right in the HLL leads to
00 80 00 00
but one would hope that the shr for shift right instruction would
instead leave:
00 00 00 80
so I am wondering if besides using assembler instructions there are
other well known methods in the high level language for shifting,
particularly in terms of one bit shift and multiples of eight bit
shifts.
That's basically about the conflict between msb->lsb bit fill order but
LSB->MSB, LE or Little-Endian byte order, and correspondingly between
lsb->msb and MSB->LSB, BE or Big-Endian, in terms of high level shift
and instruction level shift. I have not decompiled the output of the
compiler on the LE machine, maybe that would be the most direct way to
see what the compiler does to accomplish bit shifts across byte
boundaries that preserve numeric values, but if you happen to know
offhand, that would be interesting and appreciated. I'm basically
looking at the basic necessity of assembler for a bit scanner. It is
acceptably easily done in the HLL, I'm just concerned about trivial
issues of compiler instruction generation.
Here's another question, but it's about the linker. Say, a unit
contains multiple symbols, that have by default the extern storage
class. I guess it's up to the linker to either draw in all symbols of
the module or pull the used symbols out of the compiled module. I look
at the output with gcc, and it draws in symbols that are unused, just
because some other symbol in the same compilation unit is used. for
example:
[space:~/Desktop/fc_test] nm Build/test
....
00003c7c T _fc_mem_free
00003c38 T _fc_mem_malloc
00003cc4 T _fc_mem_realloc
00003d10 T _fc_mem_stackalloc
00003d6c T _fc_mem_stackfree
....
All of those definitions are in the same compilation or translation
unit, but only fc_mem_stackalloc and fc_mem_stackfree are actually
used, and there is no reason for that code to be in the output. I
change the optimization to -O3 and the unnecessary symbols are still
there.
[space:~/Desktop/fc_test] space% cc -v
Reading specs from /usr/libexec/gcc/darwin/ppc/2.95.2/specs
Apple Computer, Inc. version gcc-926, based on gcc version 2.95.2
19991024 (release)
It's one consideration to divide the compilation units so that each
compilation unit contains only one function, but that gets very bulky,
as some of the translation units in this project have dozens of nearly
identical functions, and I would rather not have hundreds of source
code files if I could hint to the linker to remove unnecessary code.
Some programs linking to the static library only need one of those
hundreds of generated functions.
So:
1. variadic function arguments going to called variadic function?
2. HLL shift on Little-Endian?
3. linker hints for unneeded symbols besides compiling into separate
units
Then I have some questions about best practices with signals, Microsoft
SEH or Structured Exception Handling, portability and runtime
dependency of longjmp, and stuff.
Thank you!
Ross F.