My thanks once again. Things are now gradually starting to come together.
I should first clarify that we never manipulate the time field - it's the precise 32-bit bit pattern (time) that gets sent to the outside world that matters, not what gpc Pascal (or any language/compiler) actually uses to hold the 32 bit time field.
I am not yet a gpc user and was unaware of the type casting approach. (My last Pascal experience was some years ago and that was on mainframe/mini-computers, not in the PC/Linux world. Since then I've worked in ADA and greatly liked that language.) Type casting is exactly the KISS approach I was looking/hoping for. In great preference to the fragile and potentially non-portable approaches of variant records or the parameter mapping "trick" at the library interface.
Also new to me are the gpc bitwise operators, thanks for mentioning them. They will be a great help in rewriting parts of our code.
Once I get "Hello World" working I'll be spending some time with the current gpc manual to see what else in gpc is new to me. I expect I will find other things in gpc that will be of immediate practical use to us. Hopefully the manual also covers how to create GPC makefiles that use individually compile multiple source files, persistent object files and a separate user controllable linker step.
As surmised, the time taken to build a message is not (yet) time-critical. However "endian-ism" might (but shouldn't) become an issue. We do not manipulate the time and not care how the bytes are actually stored because it's only the bit pattern of the "4 byte time field" that matters when the message is sent.
The current conceptual model (without type casting) is:
GetSystemTime( X ) - return 32 bit time in X (as a 4 byte string)
Y = X + rest-of-message - concatenate strings to get final message string SendMessage( Y ) - hardware sends the final message sting
As revised to use type casting (using the types at the end of this message):
GetSystemTime( Z ) - return the time in Z (Z is defined as 32 bits) X = Char4( Z ) - cast the 32 bit time to a 4 byte string Y = X + rest-of-message - concatenate strings to get final message string SendMessage( Y ) - hardware sends the final message string
So why use a 4 byte string and not something else? Everything else in the application uses strings - which makes using a string the simplest way for us to handle the 32 bit time field.
Comments? Improvements?
Thanks.
BTW, My viewpoint is that if something can be done in an easily understood (=KISS) manner using only standard gpc Pascal constructs (i.e. without "tricks" or "virtuous" (=often obtuse) coding) it is "pure" Pascal. By those standards only the second version is "pure" Pascal.
-----Original Message----- From: gpc-owner@gnu.de [mailto:gpc-owner@gnu.de] On Behalf Of Frank Heckenbach Sent: September 7, 2010 08:03 PM To: gpc@gnu.de Subject: Re: Null characters in strings
Morton, John wrote:
My thanks for confirming that writeln is not implemented using C's printf function (I can't remember where I got that idea) and that
gpc's
writeln can send all 256 characters (absolutely necessary to handle binary time as a string).
On reflection I realize I have misstated our problem. But I think I also have a work-around for it.
The issue is that the supplied library returns the time as a 32 bit binary value. The problem is essentially how to coerce the 32 bits
into
a corresponding 4 character gpc string. (BTW, they are the first 4 bytes of every message sent by our application).
I had hoped that the coercion (effectively a type cast) would be easy
to
accomplish within Pascal. I then thought about variant records but
that
did not seem feasible. I have since realized that the conversion could be done where we
define
the interface to the external routine. In the Pascal function definition use a 4 character fixed length string for the time field
and
have the linker map that string to the corresponding 32 bit value
field
used by the library (probably by using pass-by-address, possibly pass-by-value). Not a pure Pascal approach but a practical one - as long as you are
well
aware of the pitfalls. (In the "pure" approach the Pascal interface parameter would be a 32 bit unsigned value that gets converted/mapped
by
Pascal to the corresponding 4 byte string).
The only "pure" Pascal approach would be converting the value to single bytes using "div"/"mod" (GPC also supports bitwise "and" and "shl"/"shr") and then to characters using "Chr". If it's not time-critical, this might actually be worth considering, since it avoids endianness issues.
With GPC, also type-casting should work. Something like this:
program Foo;
type Card32 = Cardinal attribute (Size = 32); Char4 = array [1 .. 4] of Char;
var a: Card32; b: Char4;
begin b := Char4 (a); a := Card32 (b); end.
Variant records are sometimes abused(!) for this purpose, but I don't recommend it.
Frank
Morton, John wrote:
Hopefully the manual also covers how to create GPC makefiles that use individually compile multiple source files, persistent object files and a separate user controllable linker step.
I don't think there's much about it in the manual.
- GPC has an "--automake" option that recursively invokes GPC to compile all modules. However, it has problems in tricky situations (involving cyclic dependencies), and does not support a user controllable linker step.
- The external GP utility (http://fjf.gnu.de/misc/gp.tar.bz2) is meant to replace automake, and will also call GPC for all modules and for linking. By default, linking is not user controllable. However, you can use the options "-c" (don't link) and "--print-objects", and then do what you need to with the objects. Also, the source of GP is written in Pascal, so you can modify it yourself if necessary (procedure Link might be the start to look at). If you make your changes in generally useful form (i.e., options, rather than hardcoding what you need), you can send the patch here, so I can integrate it (but, of course, you don't have to -- the GPL also allows making your own private changes).
- Of course, you can also hand-write a Makefile, C style. GP itself, in order to avoid a chicken-and-egg problem, contains such a Makefile (requires GNU make). It's probably more generalized than you need (including support for cross-compiling, support for Dos/Windows peculiarities, rules to build documentation, etc.), so you can probably do with something simpler.
Frank