things i would ban from clc

D

Don Y

Hi James,

That requires us to be able to correctly interpret Limbo code. You know
Limbo, I don't, and I suspect that such ignorance is fairly common here.
It should be incumbent on you, not us, to provide a translation.

A translation of the Limbo code appears at the end. Expecting *me*
to come up with a C version that uses features THAT I DIDN'T KNOW
EXISTED as of a few hours ago would be as prepostrous as me asking
you to tell me why C's approach is better than a Limbo approach --
and expecting *you* to provide that Limbo example! (assuming you've
never seen Limbo code until the same point in this thread that *I*
was informed of said:
Even if I were familiar with Limbo, I'm not competent to provide a
counter-example, and never claimed to be. I've written highly parallel
code - a quarter century ago, using a non-conforming C compiler, a
highly idiosyncratic operating system, and a concept that I no longer
remember the name of that was significantly different from the concept
of threads.
I've written ordinary POSIX threaded code - but that was just for fun,
about two decades ago, and I never even got it running, because I had
more urgent work that I was actually being paid to do. I've only just
started familiarizing myself with C2011 threads; I'm not ready to write
anything using them.
Understood.

As the complainant, you should be competent to provide an example of the
problem you're complaining about - without such expertise the problem
could just be due to your lack of familiarity with the system. Not many

Exactly. I have no interest in waiting for a C2011 implementation
people are C2011 threading experts yet; I'd happily accept as relevant
an example using any other well-known threading system with a C
interface, such as POSIX threads. As I indicated above, I wouldn't be
competent to judge your example, but other people on this forum would
be; presumably including Ben Pfaff.

greetings(
surname: string, # parameter of type "string"
children: list of (string, int) # a list of tuples each
# consisting of a string and an int
output: chan of string # communication channel named "output"
# that conveys strings
) {
# create a string by concatenating the two string constants
# with the string *variable* passed to the function as "surname"
# pass the resulting string out the channel named "output"
output <-= "Season's Greetings from the "
+ surname + " family!\n";

# as long as the "children" list is not empty...
while (children != nil) {
# extract one the first ("head") element from the "children"
# list assigning it's component values to "firstname" and "int"
# the presence of the ':' is a syntactic shortcut that allows
# the declaration of these variables to be deduced from the
# values assigned to them (i.e., we know children consists
# of (string, int) tuples so we know "firstname" is now declared
# as a string and "age" is an int. I.e., this just saves two
# lines declaring those types as
# firstname: string;
# age: int;
(firstname, age) := hd children;

# ':' tells you that description is of the same type as the
# rvalue -- a string (since the expression on the right is
# recognizable as a string). Set the description string
# variable to the concatenation of the "firstname" and "surname"
# strings -- with a constant string (whitespace) in the middle
description := firstname + " " + surname;

# tack on the parenthetical comment indicating the child's age
# note the use of '=' instead of ":=" -- since we have already
# declared description's type
description = description
+ " (" + age + " years old)";

# pass the "fullname" (grrr... should have been "description")
# string to the communication channel named "output"
output <-= fullname;

# assign the balance (everything beyond the "head") of the children
# list to the children list variable
children = tl children;
}
}


logging(
input: chan of string # communication channel named "input"
# that conveys 'strings'
) {
sys = load Sys Sys->PATH; # a variable that holds a reference to
# a module called Sys. Sys->PATH
# is a constant defined within that
# module indicating where it is

while (FOREVER) {
# text is a string (because it's type is derived from the
# rhs type -- which is "chan of string"
# It's value is assigned from the string fetched from the
# communication channel named "input"
text :=<- input;

# use the print() member of the module referenced by "sys"
# to print a string "somewhere" (i.e., like printf)
sys->print("%s\n", text)
}
}


job(surname: string,
children: list of (string, int) # you've seen this before...
) {
pipe: channel of string; # declare "pipe" to be a communication
# channel (should have been "chan") that
# conveys "string" data types.

# create a thread that executes the "logging" function (defined
# above). Pass it a communication channel that it will use to
# watch for incoming text
spawn logging(pipe);

# create a thread that executes the "greetings" function (defined
# above). Pass it the communication channel that it should use
# to interact with the "logging" function started above. Pass
# the surname and list of children's (names, ages) to that
# function (i.e., thread) so that it has some work to do.
spawn greetings(surname, children, pipe)
...
}

I.e., anything that doesn't say "chan" or "spawn" in the above
is "application" and unrelated to the tasking aspects of the
language.
 
D

Don Y

Hi Keith,

I think<threads.h> was made optional mostly to ease the burden
on implementers, and encourage them to develop conforming
implementations when they otherwise wouldn't.

I think this is just another aspect of C's "light touch".
It tries not to be "imposing" (Ada, anyone?) so you can
use as little of it as you need/want.

E.g., you don't *have* to use strlen() to determine the
length of a string. You don't *have* to use printf()
to pass text to the outside world. You don't *have* to
use array notation to access a group of contiguous like-typed
values.
 
D

Don Y

Hi Kaz,

Those who reinvent wheels just don't know how to use Google.

Or, can't find a wheel that is durable enough, big enough,
small enough, wide enough, smooth enough, etc. for their
needs!

But, that doesn't mean they should experiment with SQUARE
ones!
 
T

Tim Rentsch

Don Y said:
Don Y said:
Why not support for *tasking* -- native to the language
(instead of in a library!) like Limbo?
[...]

The 2011 ISO C standard includes (optional) support for threading.

See<http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf>
section 7.26.

OK. But that's just another standard library. The language
itself doesn't include those provisions. [snip re: Limbo]

Even though it is optional, support for threading is not just
another library, and that is important - for threads to work, the
language definition needs to be augmented so that the semantics
of inter-thread operations is well-defined. Furthermore the
visible language (as opposed to library) for C was itself changed
to accommodate threads, eg, '_Thread_local' storage class
specifier.
 
T

Tim Rentsch

(to repeat myself, IMO this statement is inaccurate for C2011.)

What's the advantage of putting threading into language instead
of the library? (You explained *how* Limbo integrates threading
into the language, but not why it does.)

I assume most people in the group have seen this, but for those
who have not:


Threads Cannot be Implemented as a Library

Boehm, Hans-J.

HPL-2004-209

Abstract: In many environments, multi-threaded code is written
in a language that was originally designed without thread support
(e.g. C), to which a library of threading primitives was
subsequently added. There appears to be a general understanding
that this is not the right approach. We provide specific
arguments that a pure library approach, in which the compiler is
designed independently of threading issues, cannot guarantee
correctness of the resulting code. We first review why the
approach almost works, and then examine some of the surprising
behavior it may entail. We further illustrate that there are
very simple cases in which a pure library-based approach seems
incapable of expressing an efficient parallel algorithm. Our
discussion takes place in the context of C with Pthreads, since
it is commonly used, reasonably well specified, and does not
attempt to ensure type-safety, which would entail even stronger
constraints. The issues we raise are not specific to that
context.

http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf
 
K

Kaz Kylheku

Hi Kaz,



Or, can't find a wheel that is durable enough, big enough,
small enough, wide enough, smooth enough, etc. for their
needs!

Most importantly: invented here enough.
 
D

Don Y

Hi Kaz,

Most importantly: invented here enough.

I don't see that, much. I see more of a trend away from
"roll your own" towards more of a "plug in systems".
People seem (finally?) to not want to muck with much
of the "mechanism" involved in solving problems.

And, with multicore, GHZ CPUs, people are becoming even
lazier in how much they "push" the platform: "By the
time we finish the project, the hardware will be twice
as fast/cheap/etc."
 
D

Don Y

Hi Tim,

(to repeat myself, IMO this statement is inaccurate for C2011.)


I assume most people in the group have seen this, but for those
who have not:

Threads Cannot be Implemented as a Library

Boehm, Hans-J.

HPL-2004-209

Abstract: In many environments, multi-threaded code is written
in a language that was originally designed without thread support
(e.g. C), to which a library of threading primitives was
subsequently added. There appears to be a general understanding
that this is not the right approach. We provide specific
arguments that a pure library approach, in which the compiler is
designed independently of threading issues, cannot guarantee
correctness of the resulting code. We first review why the
approach almost works, and then examine some of the surprising
behavior it may entail. We further illustrate that there are
very simple cases in which a pure library-based approach seems
incapable of expressing an efficient parallel algorithm. Our
discussion takes place in the context of C with Pthreads, since
it is commonly used, reasonably well specified, and does not
attempt to ensure type-safety, which would entail even stronger
constraints. The issues we raise are not specific to that
context.

http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf

I think the problem being addressed, here, boil down to
removing the need for the developer to "take precautions"
(i.e., manually ensure that the compiler doesn't "get ahead
of him") along with wanting to be able to use the language
to *efficiently* implement truly parallel threads of
execution.

In practice (at least in the applications I've designed),
you partition an application with an eye towards keeping
individual threads "disjoint". "Communication is
expensive" so you want to minimize the amount of data
that has to be shared between threads (and processes,
too, but that's another level).

As you reduce the communication interconnects, the relative
cost of synchronization, mutual exclusion, etc. drop. So, the
cost to *implement* them can creep up without having dramatic
effects on the overall performance of the application.

I.e., a truly parallel approach to a problem having multiple
threads (possibly executing on SMP) each actively accessing
the same data set is impractical with the overhead of library
calls (even if they are lightweight).

OTOH, having one thread do <something> and another thread
doing <somethingcompletelydifferent> -- with little or no
interaction between them -- incurs very little added cost.

If you want to allow the programmer to divorce himself
from this responsibility (?), then the compiler has to
take a more active role in guaranteeing this behavior.
 
G

Guest

Do dsp having 32 bit chars, use 4 times memory for represent
the same 0..255 ascii .txt?

you'd have to ask someone who's used such a device; but yes i believe so. Everything's 32 bits. Note DSPs typically don't do a lot of string processing.
what about assembly program instructions?

not a clue. Maybe code is different from data. But I'm guessing wildly.
their program take more space in memory?

i not see any other danger on that but only conversions must
be ok for comunicate other computers...

C places no requirements on implementions that they must be capable of communicating with other computers. But yes, producing strings of bytes must be a bit of a pain.
 
J

Jens Gustedt

Am 03/13/2012 11:09 PM, schrieb James Kuyper:
I've written ordinary POSIX threaded code - but that was just for fun,
about two decades ago, and I never even got it running, because I had
more urgent work that I was actually being paid to do. I've only just
started familiarizing myself with C2011 threads; I'm not ready to write
anything using them.

Just as a side note, C11 threading is basically POSIX threads with
reduced tuning functionality. It is relatively easily emulated by
POSIX threads. (There is just one major issue with the return type of
the thread functions, POSIX has void* where C11 has int)

I have written a lightweighted emulation in that sense that you could
check out to improve your practical skills :)

Jens
 
D

Don Y

Hi Nick,

you'd have to ask someone who's used such a device; but yes i
believe so. Everything's 32 bits. Note DSPs typically don't do
a lot of string processing.

Of course, you can *pack* smaller data into those "words"
but extracting them isn't as simple as saying "foo".

I designed a processor many years ago with 16b memory.
When we ran our first test program on the hardware,
*nothing* worked. This was devastating. I was 102% sure
the microcode in my processor was correct/working (I had
debugged it at DC). And, my faith in the guy who wrote
the code was unquestionable!

We eventually realized that I had designed the instruction
set assuming all addresses were for "16b data". I.e.,
there were no "bytes" in memory. The guy who wrote the
software assumed the more typical interpretation of
"byte addressable" memory. When we eventually realized
this ("Um, didn't you notice that all of your addresses
had a '0' in their rightmost bit? Knowing *me*, do you
think I would have wasted that bit in the instruction
format??") it was a trivial change to the code generator
to ensure the addresses in the code matched the addresses
that the instruction decoder expected! :-/

"Colossal mistakes that almost were!"
not a clue. Maybe code is different from data. But I'm guessing wildly.

Different DSP's have different capabilities and, thus, different
data types that they can support. E.g., some are geared towards
floating point operations while most stick to the integer realm.
C places no requirements on implementions that they must be capable
of communicating with other computers. But yes, producing strings
of bytes must be a bit of a pain.

The zero-th order summary of a DSP is: MAC as fast as possible
(Multiply and ACcumulate). If you look at the die, you see
that a disproportionate amount of it is dedicated to crunching
numbers (instead of managing memory, decoding instructions, etc.)
 
D

Don Y

i see above as:

#define R return
#define G goto
#define u8 unsigned char
#define u32 unsigned

// at end of progr someone has to free the list children
i32 greetings(
u8 *output, # communication channel named "output"

No. The *data type* of "output" is "communication channel".
There is no counterpart in C. Think of it as a "named pipe"
that connects two threads -- possibly across machine boundaries.
You could provide similar functionality with a *socket*, a FIFO
or a managed shared memory region (in some contexts). But, you
would have to explicitly set up this mechanism (function calls).

Limbo lets you just create one (and "pass it around") just like
you would an int, etc.

So, while you can accumulate the stuff intended to be transfered
across that channel *in* a string (assuming the channel is
declared to support strings -- and not ints or some other
data type!), you still have to actively *pass* it across
some communication mechanism.

Threading implies communication between threads. Channels
formalize that.
u8 *surname, # parameter of type "string"
u8 *children # a list of tuples each

Not sure how you plan on storing those, yet... Note that Limbo
makes it clear what you are intending *in* the declaration:
"This is a LIST of TUPLES where each is tuple consists of
a string (the child's name) and an integer (his age)"
) {u8 *tmpStr, *tmpPlist;
i32 r=0;
if(surname==0||output==0||children==0||ListNotOk(children))
R 1;

# create a string by concatenating the two string constants
# with the string *variable* passed to the function as "surname"
# pass the resulting string out the channel named "output"
# output<-= "Season's Greetings from the "
# + surname + " family!\n";

// StrMultiCat(u8** , ...) where ... are C string u8*
if( StrMultiCat(&tmpStr, "Season's Greetings from the ",
surname, " family!\n" )==-1 )
{err:
StrDel(&tmpStr); R r
}

Notice that you have to explicitly manage memory (to avoid leaks).
Limbo ensures that the resources you hold are automatically
free-d when you terminate. I.e., it is part of the *language*
specification, not the "hosting environment".
if( StrSPut(output, tmpStr) == -1) {r=5; G err;}

Again, all you have done is built a string. No one else
can *see* it! You haven't, yet:

# pass the resulting string out the channel named "output"
# as long as the "children" list is not empty...
tmpPlist=0;
// NextListElement of 0 is the first element of the list
// [or 0 if it is a void list]
// NextListElement of the last element of list is 0
while(NextListElement(&tmpPlist, children)) != 0 ) {
# extract one the first ("head") element from the "children"
# list assigning it's component values to "firstname" and "int"
# the presence of the ':' is a syntactic shortcut that allows
# the declaration of these variables to be deduced from the
# values assigned to them (i.e., we know children consists
# of (string, int) tuples so we know "firstname" is now declared
# as a string and "age" is an int. I.e., this just saves two
# lines declaring those types as
# firstname: string;
# age: int;
// firstname: u8* string
// age: u32
#(firstname, age) := hd children;

// this assign each list element, the name of children of age hd
// what is hd? or what is age?

hd = "head"

# extract one the first ("head") element from the "children"
# list assigning it's component values to "firstname" and "int"

My apologies for the typos. This should have said:

# extract one element -- the *first* ("head") element -- from the
# "children"
# list assigning it's component values to "firstname" and "AGE"

I'd have thought the intent would have been obvious even if the
commentary was crap :>
if( StrMove(tmpPlist, children)==-1 ) {r=6; G err;}
*(u32*)(tmpPlist+4)=hd;

# ':' tells you that description is of the same type as the
# rvalue -- a string (since the expression on the right is
# recognizable as a string). Set the description string
# variable to the concatenation of the "firstname" and "surname"
# strings -- with a constant string (whitespace) in the middle
#description := firstname + " " + surname;
if( StrMultiCat(&tmpStr, firstname, " ", surname)==-1 )
{r=7; G err;}

# tack on the parenthetical comment indicating the child's age
# note the use of '=' instead of ":=" -- since we have already
# declared description's type
#description = description
# + " (" + age + " years old)";
// you not say what the age is...

See above comment. (firstname, age) can be though of as
struct {
char *firstname;
int age;
}

The "children" list could be implemented as either a linked list
of these structs *or* an array -- with suitable code wrapped
around it to allow it to grow and shrink as needed.
if( StrCat(&tmpStr, " (") == -1 ){r=10; G err;}
if( StrCat_u32(&tmpStr, age) == -1 ){r=11; G err;}
if( StrCat(&tmpStr, " years old)") == -1 )
{r=12; G err;}

# pass the "fullname" (grrr... should have been "description")
# string to the communication channel named "output"
# output<-= fullname;

if( StrSPut(output, tmpStr) == -1 ) {r=13; G err;}

# assign the balance (everything beyond the "head") of the children
# list to the children list variable

# children = tl children;
not traslated: what is t1?

tl == "tail"

# assign the balance (everything beyond the "head") of the children
-------------^^^^^^^^^^^---^^^^^^^^^^^^^^^^^^^^^^^^^^
# list to the children list variable
}
StrDel(&tmpStr);
R r;
}

Notice how much "manual" work you have to do to implement the
same sorts of functionality? More opportunities for mistakes
(did you remember to free all your resources regardless of
the path you took through the code, etc.). Limbo's syntax
is a lot cleaner (though admittedly cryptic for novices)
 
A

ArifulHossain tuhin

1. it's not twos' complement

2. an 'int' may have a trap value

-who- -cares-
go have sex with youselves

thanks to this post, i have looked through ccl. it looked very neat. whenever we start a new project, we start by writing list/hashtables stuffs first.. even before the design of the project itself finalized. because we know no matter what we are going to need them, and because of the application's diversity we have to modify our old list/hash modules to an extent that its easier to write a new one.

only complain i have with jacob's library is naming convention. i do not like "thisThat". "ths_tht" suits me better.
 
T

Tim Rentsch

io_x said:
where is the wrong on this below? where are difficulties?
there is one u32 space for the struct that
is used from OS for the thread signals

for example:
// global to all threads
#define u8 unsigned char
#define u32 unsigned

u8 *thisIsAList;
List(&thisIsAList); // create the list memory, and inizilize
if(thisIsAList==0) return "this is one errror";

// local thread
Lock(thisIsAList);
// for example the first u32 of the list, point to the memory
// the OS use for block, for multhread
Operations(thisIsAList);
UnLock(thisIsAList);

Here is a reference for a paper that explores the issues.

Threads Cannot be Implemented as a Library

Boehm, Hans-J.

HPL-2004-209

Abstract: In many environments, multi-threaded code is written
in a language that was originally designed without thread support
(e.g. C), to which a library of threading primitives was
subsequently added. There appears to be a general understanding
that this is not the right approach. We provide specific
arguments that a pure library approach, in which the compiler is
designed independently of threading issues, cannot guarantee
correctness of the resulting code. We first review why the
approach almost works, and then examine some of the surprising
behavior it may entail. We further illustrate that there are
very simple cases in which a pure library-based approach seems
incapable of expressing an efficient parallel algorithm. Our
discussion takes place in the context of C with Pthreads, since
it is commonly used, reasonably well specified, and does not
attempt to ensure type-safety, which would entail even stronger
constraints. The issues we raise are not specific to that
context.

http://www.hpl.hp.com/techreports/2004/HPL-2004-209.pdf
 
T

Tim Rentsch

Don Y said:
Hi Tim,



I think the problem being addressed, here,

Did you read the paper?
boil down to
removing the need for the developer to "take precautions"
(i.e., manually ensure that the compiler doesn't "get ahead
of him") along with wanting to be able to use the language
to *efficiently* implement truly parallel threads of
execution. [snip elaboration]

The problem is the compiler is operating at the wrong level of
abstraction. Whether the compiler "gets ahead" of a developer
(a frightening concept in and of itself, but let's ignore
that) doesn't matter, because the operating environment that
(non-thread-aware) compilers generate code for doesn't make
strong enough guarantees about inter-thread or inter-processor
memory consistency. To get threads to work usably, at least
part of the compiler needs to be aware of a lower level of
abstraction, below the architectural level for a single
process (which is where essentially all pre-thread-aware
compilers operate).
 
J

Jorgen Grahn

.
I often rewrite major portions of the standard libraries
as I move from project to project -- because the execution
environments frequently differ and I don't need the "generality"
that most of the libraries provide. Or, I am bastardizing a
standard data type, etc.

When was the last time you used:

digits = INT_MAX
decimals = INT_MAX
printf("The answer is %*.*e", value, digits, decimals)

In fact, when was the last time you used the '*' flag in printf??
Will your copy of the libraries even *handle* this specific
case??

It will, on Linux and VxWorks which is where I happen to live right
now. If it doesn't, it's not C, and I have to wonder what else is
omitted.

Actually, I find that * is underused. Lots of code gets duplicated
because you want the width 9 here, but 12 there, and so on.

(Note that I'm not saying it's always wrong to hack away the support
for %e, * etc from printf().)

/Jorgen
 
B

Ben Bacarisse

Don Y said:
When was the last time you used:

digits = INT_MAX
decimals = INT_MAX
printf("The answer is %*.*e", value, digits, decimals)

Never! It needs semi-colons, and it needs the printf arguments to be in
the right order! Also, making the field width equal to the precision is
a little odd for the 'e' conversion.
In fact, when was the last time you used the '*' flag in printf??

I use it quite a lot, but that may just be that I like to parametrise my
code a lot. By the way, it's not a "flag". printf specifiers do have
flags (there are +, -, #, ' ' and 0) so using the wrong term might be
confusing.
Will your copy of the libraries even *handle* this specific
case??

It doesn't need to. printf need only support conversions that generate
no more than 4095 characters.

<snip>
 
D

Don Y

Hi Ben,

Never! It needs semi-colons, and it needs the printf arguments to be in
the right order! Also, making the field width equal to the precision is
a little odd for the 'e' conversion.


I use it quite a lot, but that may just be that I like to parametrise my
code a lot. By the way, it's not a "flag". printf specifiers do have
flags (there are +, -, #, ' ' and 0) so using the wrong term might be
confusing.

Wow, I am *so* relieved! With all your criticisms, I was
afraid you might not have UNDERSTOOD WHAT I INTENDED! Whew!
Glad I won't have to worry about *that*!

[If you have some EXTRA free time, how about checking my past
posts for spelling and grammatical errors. It might help
others who are confused by a typo here or there... e.g., my
recent use of 'int' in place of 'age'... There might be
*other* folks who would also welcome your attention to this
level of detail!]

Of course, aside from the obligatory picking of nits, you
*did* (?) realize that the point I was making to Jacob was that
certain things are moved into LIBRARIES vs. part of the
language "proper" so that they *can* be elided from
particular applications without compromising the language's
functionality. That you can still successfully deploy an
application with a printf(3) implementation that *won't*
handle the case illustrated above.

You can't elide "int's" from C. Nor support for arrays. etc.
It doesn't need to. printf need only support conversions that generate
no more than 4095 characters.

You may be lucky enough to work in environments where you
can be assured that the tools are strictly conforming AND
when you encounter something that *isn't*, your employer/client
is willing to wait for <someone> to fix it so you can get back
to work.

But, if you look at a wider range of products claiming to
be "C compilers", you will find these sorts of "problems"
are commonplace. When confronted, the vendor will often
skirt the issue with "Well why would you want to do *that*?"
(instead of addressing a documented PROBLEM, let's infer
that the developer is doing something 'wrong' or that could
be done in a DIFFERENT manner).

I work with a *lot* of compilers for a lot of different
iron. I've taken up the practice of adding examples of
test cases that I've encountered that weren't well-behaved.
I apply that test suite as one of the first things I do
when using a "new" compiler to see what sort of confidence
I can have in its results.

As I spot things that don't work, I gauge how much I will
either have to *avoid*, *fix* or replace with my own
library components. Or, how strong a case I will have to
recommend to client that he abandon a particular toolchain
in favor of another ("What *exactly* is wrong with the
product we purchased? We've got a lot of money invested
in those tools! Not to mention several deployed products!")
 
D

Don Y

Hi Jorgen,

It will, on Linux and VxWorks which is where I happen to live right
now. If it doesn't, it's not C, and I have to wonder what else is
omitted.

Exactly. If you are the proprietor, then *you* can decide
how much effort to expend figuring out what's missing/broken.
Or, simply abandoning the tool in favor of something you
*know* "works".

OTOH, if that decision comes from "on high", you can gripe all
you want but you're still going to have to *live* with it!
Actually, I find that * is underused. Lots of code gets duplicated
because you want the width 9 here, but 12 there, and so on.

Yes! And, if you're like me and drive lots of algorithms
from tables, every place you can eliminate a hard constant
is a blessing!

But, I find many libraries use fixed size, internal buffers to
perform these conversions. Or, allocate a "huge" buffer
which might exceed available memory. The desired functionality
can be obtained with a small buffer (~LDBL_DIG) and more
*smarts* in the implementation. E.g., fprintf() should be
able to support "printing" thousands of digits with no more
than ~100 bytes of R/W memory dedicated to its own use.
(Note that I'm not saying it's always wrong to hack away the support
for %e, * etc from printf().)

OTOH, there are applications where all of printf's different
formats are just excess baggage. The size of printf()'s
executable is *staggering* when you think of how "little"
it (appears to) does. Yet, it seems to be one of the first
modules that a developer draws into his project...
 
J

jacob navia

Le 15/03/12 20:26, Don Y a écrit :
OTOH, there are applications where all of printf's different
formats are just excess baggage. The size of printf()'s
executable is *staggering* when you think of how "little"
it (appears to) does. Yet, it seems to be one of the first
modules that a developer draws into his project...

I know, I have written printf for my compiler system lcc-win.

It is quite big mind you:

d:\repos\lcc-src\libc>pedump /summary xprintf.obj
xprintf.obj 41871 bytes, linked Tue Mar 13 19:22:37 2012

Section Name Size
01 .text 14780
02 .data 1112


almost 15K, + 12 K for character strings, tables, etc...

But it will print a denormalized number extracting all the
available precision from it.

Supports all the C99 formats, etc. Actually printf is a
run time intepreter of the format string. My printf also
must support all the extensions: 450 significant digits
qfloats, printng the comma separator to separate the number
in thousands, and many other "goodies".

I would like to have to possibility of trimming it, something
like "slimPrintf()" but it would make programming more complex
than it needs to.

And with only 15K, it is not THAT big, compared to other
implementations that do less with more.

jacob
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,079
Messages
2,570,575
Members
47,207
Latest member
HelenaCani

Latest Threads

Top