Re: Is C99 the final C? (some suggestions)

From: Sidney Cadot (sidney_at_jigsaw.nl)
Date: 12/09/03


Date: Tue, 09 Dec 2003 01:44:21 +0100

Paul Hsieh wrote:

> In article <br0f1q$gnr$1@news.tudelft.nl>, sidney@jigsaw.nl says...
>
>>Paul Hsieh wrote:
>>
>>>I run into this every now and then. For example, I was recently trying to
>>>solve the following problem: Create a directed graph on n points, each with an
>>>out degree of d (I am concerned with very small d, like 2), such that the path
>>>length between any pair of points is minimized.
>>>
>>>Turns out that this is a problem whose complexity grows super-exponentially
>>>with very small values of n. Despite my best efforts, I don't know the answer
>>>for n=11, d=2 for example (I know its either 3 or 4, but I can't prove that its
>>>not 3). More startling is the possibility that n=12,d=2 might have a smaller
>>>latency (but I don't know that either)!
>>
>>I used to do programming contests in university (both as a participant
>>and as a judge later on), so I quite like this sort of problem. Care to
>>provide some background (via regular e-mail), I think I'd like to think
>>about this for a bit.
>
>
> This isn't a rigged contest problem. This is a real world problem.

I think you forgot the capitals on Real World, there... :-)

> Imagine a
> *SERVERLESS* online game topology. How do you communicate "game-moves" in
> realtime between players in a way that is most efficient and with the least
> perceived lag, given a limited amount of bandwidth? Solve the above problem,
> and you have a solution for this problem. (Actually for games you can crank d
> a little higher than 2 -- the exact problem that I am looking at is different,
> and I am loathe to increase d above 2.)

Just out of curiosity: why should the graph be directed; don't the nodes
have two-way communication? And you're not considering a lag metric
other than just number of hops?

> You can think about this problem all you like. If you want to know if I am
> fully of it or not, see if you can get above n=10,d=2.

Perhaps I will, I'll have some time on my hands round Xmas. Sounds like
a nice problem.

>>>Anyhow, the point is that the only way to have a chance to squeeze enough
>>>computational juice out of my PC to solve this, I had to hard code huge amounts
>>>of the code, and use a lot of bit twiddling tricks just for each special case.
>>>I used the preprocessor macros as much as possible to make my code manageable,
>>>but in order to change n, I actually have to *modify* the code by adding and
>>>changing *n* lines of code. There's not much I can do about this, I would have
>>>no chance to solve this otherwise.
>>
>>Ok, that's a case. But wouldn't it have been better then just to make a
>>program generator (written in C or something else)? Or perhaps use the
>>m4 macro processor?
>
>
> Tell me how you do this in a way that's compatible with testing it against 3
> different compilers (one of the *OTHER* techniques I use to go after
> performance ...) two of which are very unfriendly to being commandline driven,
> while still making sense from a debugging point of view?

How about generating C source that you #include from a resident file in
your project, would that be an option?

>>>>>I'm saying that trying to fix C's intrinsic problems shouldn't start or end
>>>>>with some kind of resolution of call stack issues. Anyone who understands
>>>>>machine architecture will not be surprised about call stack depth limitations.
>>>>
>>>>It's the task of a standard to spell these out, I think.
>>>>
>>>>
>>>>>There are far more pressing problems in the language that one would like to
>>>>>fix.
>>>>
>>>>Yes, but most things that relate to the "encouraging of writing
>>>>extremely unsound and poor code", as you describe C, would be better
>>>>fixed by using another language. A lot of the inherently unsafe things
>>>>in C are sometimes needed, when doing low-level stuff.
>>>
>>>Why is UB in isgraph(-1) needed? Why is UB in gets() needed? Why is the fact
>>>that fgets() skips over '\0' characters needed? Why is a non-portable right
>>>shift on signed integers needed (especially considering the one on unsigned
>>>*is* portable)?
>>
>>These are side cases, that are at least mentioned in the standard. No
>>big deal, IMHO.

> Its a big deal to me. I don't own any material on the C language that
> specifies all of this.

> I actually go reference source code for a C library I
> happen to have access to. But, of course, these sources and a real world
> programmer's sense leads me to the very wrong conclusion that isgraph(-1) just
> returns false.

The C standard specifies what is UB and what's not. Grepping an
implementation is a fragile way of dedicing semantics, I would say.

>>[...] This is much more of a big deal:
>>
>>int count_nodes(struct Tree *t)
>>{
>> return t ? count_nodes(t->left)+count_nodes(t->right)
>> : 0;
>>}
>>
>>Things like this are ubiquitous in many kinds of code.
>
> Uh ... dude, that just looks like an expensive way of writing:
>
> int count_nodes (struct Tree *t) {
> return 0;
> }

Hmmm yes, it is, isn't it? Now I feel all silly!

> I don't suppose you did very well on these programming contests did you? Btw,
> weren't you railing against trigraphs?

Held my own, thank you very much. And yes, I was railing against
trigraphs. Why do you ask? There's no trigraph in the code.

>>[...] Trees with a big depth are not uncommon.
>
>
> Assuming you actually wanted to count the *NODES* of the tree, and were a
> little concerned about performance try this:
>
> static int count_nodes_inner (const struct Tree *t) {
> return (t->left ? (1 + count_nodes_inner (t->left )) : 0) +
> (t->right ? (1 + count_nodes_inner (t->right)) : 0);
> }
>
> int count_nodes (const struct Tree *t) {
> return t ? count_nodes_innter (t) : 0;
> }
>
> as it avoids the leaf node tail calls, which will roughly double the
> performance.

Well, I'm glad that you extracted my intended meaning from the name of
the function I used. Good thing I didn't use an operator! ;-)

>>[...] How can I ever claim such a function is portable if I have no
>>guarantee whatsoever that it will work on some architectures?

> Huh? Are you talking about the stack thing again?

I'm _still_ talking about 'the stack thing' yes, since you still seem to
think that this is a triviality. I think it's not.

Dude: malloc (65536) is not portable by the same reasoning, and:

If you think that, then you didn't follow my reasoning. I can find out
at compile time if malloc(65536) is allowed, and if it is, I can find
out at runtime if it has succeeded. I can do no such thing with stack
overflows. The program will exhibit all the symptoms of UB without a
proper cause that can be traced down to the standard.

> int fib(int n) {
> if (n <= 2) return 1;
> return fib(n-1) + fib(n-2);
> }
>
> isn't going to work in any relevant way in any language, for a call like
> f(1000000).

What are you trying to say here? Help me out a bit.

> You simply do not understand. Malloc and multithreading are intertwined in the
> implementation. If you have multithreading, they you have to lock and unlock
> your heap, or use other strategies to make sure one thread isn't in the middle
> of freeing while another is mallocing. If you don't, it introduces something
> called a "race condition". Without exact considerations malloc and free would
> simply fail to function properly in a multithreaded environment.
> The point is that any extensions of the heap's semantics end up having exactly
> the same problem. For example, how would one write a "freeall()" on top of
> malloc? (Ignoring the fact that writing it *ON TOP* of malloc/free loses all
> the potential *MASSIVE* performance advantage) Well presumably you'd have some
> hidden part at the head of each allocation creating a linked list of
> outstanding mallocs that were removed upon frees, and the freeall() function
> would just walk through them calling free one by one. In a multithreaded
> environment, once again, you'd be in race condition city. Same problem for
> trying to build seperated heaps (virtual or otherwise.)
>
> Now the C language standard says nothing about this of course, because C
> doesn't say anything about multithreading at all. But that doesn't make the
> problem go away -- most of the commonly used C compilers today include
> multitasking extensions.

Are you sure you mean "multitasking" (which deals with processes,
usually each having their own address space) rather than
"multithreading" (which deals with threads of execution within the same
process, sharing the address space)?

I still seem to be missing your point rather blatantly, I'm afraid.

> The point is that there is a *HUGE* difference between pushing such
> functionality into the C standard, versus trying to obtain them from 3rd
> parties. If it were put into the standard, then each vendor could modify their
> heap implementation (a quite doable endeavour, since each vendor has already
> solved the heap lock/unlock problem.) But via 3rd parties, the library vendor
> has to learn and keep up to date with the OS primitives for each platform they
> support.

Ok, I'll try to summarize my understanding of the point you try to make.
  Let's consider it a priori desirable that we have a super-duper heap
manager, with all kinds of nice things like seperate heaps. We agree
that this is often useful. Now let's also assume a certain platform
where multithreading/multitasking is so important that the
platform-specific library provides support for it. We can assume that it
also sports a thread-safe malloc (yes?). You'd still want the
super-duper heap manager. Your point is that mandating a better heap
manager by the standard (without even mentioning multithreading) would
force each vendor to implement these, and implement them thread-safe if
they think multithreading is important to have. Is that close?

Now, as I see it, even if _just_ the standard malloc()/free()/etc are
thread-safe, you can build a more powerful heap manager on that alone,
using just standard C features. If the thing needs to be able to run in
a multithreaded environment, you could even do that, with some extra
effort. You need some form of mutex locking, but you can resort to
Lamport's bakery algorithm for that. Surely it won't be pretty, but it
is, in principle, possible. That's my point.

>>>>>Explain to me how you implement malloc() in a *multithreaded* environment
>>>>>portably. You could claim that C doesn't support multithreading, but I highly
>>>>>doubt your going to convince any vendor that they should shut off their
>>>>>multithreading support based on this argument.
>>
>>>>Now your shifting the goalposts.
>>
>>>How so?
>>
>>Since in your original statement there was no mention of multithreading.
>
> Mentioning the implementation malloc implicitely brings multithreading into the
> discussion. That is what you don't understand.

If the malloc returns either NULL or a pointer (i.e., it conforms
minimally to the standard) then, even in a multithreaded environment, it
is quite possible to build a heap manager on top of that. If you need
high performance even in such demanding circumstances, then, yes, you'd
need some support from preferably hardware-assisted mutexes or similar.

>> Allow me to refresh your memory:
>>
>>"But a third party library can't do this portably.

> Because of the multithreading issue ...

>>[...] Its actual useful
>>functionality that you just can't get from the C language, and there's
>>no way to reliably map such functionality to the C language itself.
>>One is forced to know the details of the underlying platform to
>>implement such things. Its something that really *should* be in the
>>language." [Paul Hsieh, 4 posts up]
>>
>>See?

> Yes -- the implicit answer to the "WHY" question that follows each statement,
> is "because of the multithreading problem". If you were aware of the issues,
> I'm sure this wouldn't be quite so bewildering to you.

Ok. Let's try to get some closure here, this is eating into my free time
too much for my taste :-)

I would say that writing a more powerful heap manager is possible in
principle, even in a multithreaded environment, as long as you have a
well-implemented malloc() (and friends) at your disposal. It would be a
drag to do so and it would be slow, but it is possible.

I think I have a clearer bearing on your statement why it would be good
to put this stuff in the library. You do need mutexes, and if the
implementation supports them, it will work better than a shared-memory
simulated mutex. So for performance reasons, I think your idea of
extending the basic heap manager, by extending its functionality as
mandated by the standard, is a good idea.

That is, as long as I can get my msize() function as well :-)

> [ skipped a bunch ]

>
>>>>>>>My proposal allows the programmer to decide what is or is not useful them.
>>>>>>
>>>>>>I'm all for that.
>>>>>
>>>>>Well, I'm a programmer, and I don't care about binary output -- how does your
>>>>>proposal help me decide what I think is useful to me?
>>>>
>>>>It already did, it seems - You just stated your decision, with regard to
>>>>binary output. Fine by me.
>>>
>>>Not fine by me. Because some other programmer who's code I have to look at
>>>will use it, and I won't have any idea what it is.
>>
>>Don't worry, you can look it up in the man pages. Unlike your
>>user-defined operators... :-)
>
>
> You would have to look up "%b" ("%db"? -- whatever) in *UP TO DATE* man pages.
> (Is *restrict* or the new *complex* type, from C99 properly documented in
> *YOUR* current man pages?)

Yes, as close as gcc is, it does. And in other cases, I have the standard.

> My proposed plug-in mechanism would be in modules
> or header files that would, one way or another, have to be in your project
> somewhere. Presumably, the source would have to be available somewhere, so
> there would be *NO QUESTION* as to what it does.
>
> Same comment applies to &&&, ||| versus user defined operators.
>
>
>>>>>Hey, its not me -- apparently its people like you who wants more operators.
>>>>
>>>>Just a dozen or so! But _standardized_ ones.
>>>
>>>And you don't see the littlest problem with this proposal? If you add a dozen,
>>>you'd better be sure that they are last dozen that anyone could possibly want
>>>to add to the language. Their value add would have be worth the pain of having
>>>everyone learn about 12 new symbols.
>>
>>Well, lets start with ?< ?> and ?: for now; ?: instead of |||, and I
>>drop the &&& requests since it is much less useful. It's already in gcc
>>so it's implementable. Give everybody 10 years to get used to it, then
>>we may add a couple more.
>
>
> My claim is that so few people would use these operators, that the would be
> defacto not supported. They would be less useful than bitfields.

Ouch! That hurts.

>>>>>My point is that no matter what operators get added to the C language, you'll
>>>>>never satisfy everyone's appetites. People will just want more and more,
>>>>>though almost nobody will want all of what could be added.
>>>>>
>>>>>My solution solves the problem once and for all. You have all the operators
>>>>>you want, with whatever semantics you want.
>>>>
>>>>That's too much freedom for my taste. If I would want this kind of
>>>>thing, I would yank out lex and yacc and code my own language.
>>
>>>Well how is that different from adding just &&& and |||? If you *REALLY
>>>REALLY* want them, then why don't you yank out lex and yacc and code up a new
>>>language?
>>
>>Because I want to use them in C programs.
>
> But I want them *not* to be used in C programs -- unless they are fully
> documented in the source. Always.

So there we differ. This, I think, is a matter of taste. I propose to
drop this subthread as well.

>>>>>What makes your code readable is adherence to an agreed upon coding
>>>>
>>>>>standard that exists outside of what the language defines.
>>>>
>>>>There are several such standards for identifier names. No such standard
>>>>exists for operator names, except: use familiar ones; preferably, steal
>>>>them from other languages.
>>
>>>Sounds like a reasonable convention to me. How about: All new operators must
>>>be defined in a central module named ----. Or: Only these new operators may be
>>>added as defined by ... yada, yada, yada.
>>
>>More handwaving... Please humour me, and spell out a reasonable
>>convention for your operator-introduction.
>>
>>>The coding standards are just different.
>>
>>I can't tell; I haven't seen a coding standard for operator introduction
>>yet.

> I just gave some.

I presume you mean "All new operators must be defined in a central
module named ----. Or: Only these new operators may be added as defined
by ... yada, yada, yada."

My mistake I guess, I overlooked these coding standards completely. I
will start promoting them within my place of work as of tomorrow :-)

> What's hand waving is saying something about stack limits --
> you haven't even suggested a way in which that *COULD* be possible
> to put down on a piece of paper.

Ah, the "tit-for-tat" technique...!

So far, nobody has challenged me to come up with a specific phrasing for
this (which actually surprises me). Here you go. It's a bit rough, but
you get the idea.

---- Proposed addition to the standard to add stack overflows:
---- Draft

a. For an active function invocation, define an upper bound for the
    amount of memory in use by this function as follows (in the
    following, denote "Upper Limit on Memory Usage" by "ULMU"):

    - For every parameter/local variable of basic type there is a
      corresponding constant macro of type size_t:

    (unsigned) char: ULMU_CHAR
    (unsigned) short: ULMU_SHORT
    ...
    double ULMU_DOUBLE
    ...
    pointer types: ULMU_POINTER

    - The ULMU for a struct shall be equal to
      the sum of upper limits of its members.
    - The ULMU for a union shall be equal to
      the maximum of upper limits of its members.
    - The ULMU for an array shall be the number
      of elements, multiplied by the upper-limit
      of its base type.

   ((the last one is certainly wasteful, but this could be refined))

    The ULMU of a function invocation shall be calculated as the
    sum of ULMU values of the types of its parameters,
    local variables, and return type, PLUS the constant
    ULMU_FUNC_OVERHEAD.

  b. The implementation shall define a macro ULMU_TOTAL,
     which will evaluate to a size_t with value at least
     4095. This value is guaranteed to remain constant during
     execution of the program.

  c. A function invocation is guaranteed to succeed only if the
     total summed ULMU values of all active function invocations
     (including the to-be active function after invocation)
     does not exceed ULMU_TOTAL.

> Its *OBVIOUS* what I am talking about above. You just
> want something specific to have something arbitrary to disagree with.

You have to trust me on this one: I'm not trying to coerce you into a
laborious writing-down of a precise rule-set, or anything. It's just
that I found that making something concrete (which you intuitively feel
should be possible) gives a lot of insight into the kind of troubles you
would get into when actually doing it.

> Just pick a convention -- if something bothers you about certain
> operators, spell it out in your convention.

As noted before, I think it would be not a good development if different
organisations settled on a different set of operators, even if they
meticulously documented their convention. Even things as simple as a
wrong (in the sense of: other than you're used to) bracing style can
hinder your productivity for quite some time before you get used to
that. Having a different set of condoned operators at each programming
shop sounds like a small tower of Babel to me.

>>>Just like freeform variable names, there is the same incumberance of the
>>>programmers managing the meaning of the symbols for more generic operators.
>>>You have not made a sufficient case to convince me that there is a real
>>>difference between the two.
>>
>>...Have you ever laid eyes on a moderately complicated APL program,
>>without knowing APL?

> No, but I have looked at the results of the annual obfuscated C code constest.
> I have never suggested that you *COULDN'T* abuse the idea. But you can abuse
> just about *ANYTHING* in C.

I'm not talking about abuse, I'm talking about the recognition capacity
of unknown operators (which is zilch, and which takes ages to get used
to). Now that's bad enough for languages, but I think it would be a
mistake of quite monumental proportions to allow some sort of C
"dialects" to emerge with different sets of operators, "operator wars",
and so on.

> You don't think adding in ||| or &&& would add to
> the potential for noise in those contests? I gave a very wordy description of
> how to define an operator -- its kind of hard to obfuscate something completely
> while you have so many hints (a keyword like _Operator, a whole function-like
> declaration, etc) as to what it is. You would have to hide it behind macros to
> truly obfuscate it, but you can use macros for arbitrary obfuscation
> regardless.

When reading the code that used (rather than defines) the operator, it
helps tremendously if the meaning jumps from the page, rather than
having to look it up in the Big Manual of Operators in use at your local
workplace.

>>The meanings you gave for these rang some bells with my programming
>>experience. It leads me to believe you have encountered similar
>>situations, which gives you some bonus points for credibility in my book
>>:-) Seriously, I don't think such operators would be a good idea, but
>>I'd welcome library functions (the old fashioned ones, with names) for them.
>
>
> Well I'd never use &&& or ||| as you proposed them for any reason whatsoever.
> At least with the <<< and @ operators, both add just enough useful
> functionality, that I *would* consider using them, knowing I would be non-
> portable. That's the point of all this -- its all just opinion. With
> redefinable operators someone's arbitrary opinion doesn't enter into it -- you
> can make it conform to whatever opinion you have.

Too much freedom is a dangerous thing, in programming at least.

> If you disagree with someone else's opinion, you can even *change* it,
> subject only to your control over the source.

It would make for an interesting experiment, sociologically :-)

A small hypothetical case study. Suppose engineer A, working on nuclear
reactor core controllers, works in a team where "?<" means "minimum" and
"#<" means "x is implied by y" for some data structure involved in logic
reasoning on the state of the system. Now he switches companies; he goes
to work on electronic toys and gadgets. Here the convention is
different, but the same operators are used.

Not much hard could be done, surely. Not unless someone from the toy
company joins the nucleare reactor programming team, that is :)

>>>Do you think perhaps its possible to use an arbitrarily extendable operator
>>>mechanism in order to *clarify* or make code actually more maintainable?
>>
>>A resounding 'no'. It's an interesting thought, but for me it falls
>>short on technical and psychological grounds, as I previously tried to
>>explain.
>
>
> You haven't shown me that it falls on technical grounds. You've just said that
> its hard to implement in the compiler -- but that's obvious.

You haven't shown me that it can be implemented in a compiler, even in
theory. That should count for something.

> [skip]

> My point is that e-commerce is not a *hardware* problem. At least, since all
> hardware supports it, its not a hardware problem. Its a software problem. The
> point is the *C* does not offer a solution for e-commerce. The Java people can
> point and laugh and say they are better for e-commerce than C, and ironically,
> they would be correct (Java has a BigNum class).

The irony would be complete if the PHB-types would fall for that... :-)

>>>Instead the hardware people waste their time on trivial little specifications
>>>like IEEE-754, which the C standards idiots don't bother to look at until 15
>>>years later.
>>
>>You shouldn't trivialize IEEE-754, it's one hell of a standard, probably
>>one of the best I have ever seen.

> You missed the implied sarcasm ...

There's a nice coding convention on operators that covers this, they're
called "emoticons" nowadays.

>>And as you are probably well aware,
>>there's a perfectly good reason why its only now that the C standard
>>committee is looking at it (only now hardware supporting it is widely
>>available). I really don't see your point here.

> Only NOW?!??! If by *now*, you mean 1991, then sure. The first IEEE-754
> implementation came out in like 1984 or so (the 8087). Within a few years,
> everyone else came on board -- Alpha (even though DEC was one of the vendors
> originally most vigorously opposed to IEEE-754), Sparc, MIPS, PPC, they are all
> IEEE-754, of course.

In '89, support hadn't spread wide enough to merit a statement (much
less an implementation mandate) on it in the standard.

>>>>[...] I guess they're pretty satisfied with the bignum
>>>>libs that exist, that provide assembly implementations for all important
>>>>platforms (and even a slow fallback for others). The reality is that
>>>>no-one seems to care except you, on this.
>>
>>>The hardware people care that it exists, and not about the form of its
>>>existence, so long as it gets used. For anyone who wants to *USE* this
>>>functionality, though, they are stuck with assembly, or third party libraries.
>>
>>What's so bad about using third-party libraries?

> From a usability point of view, GMP is crap, RSA's bignum library is crap (and
> its expensive).

How's that? How are you going to improve things by adding a carry operator?

> None of them are portable to platforms which are in
> development (you know like might be a concern for things like *SMART CARDS*.)

Now there's an application where the economy of scale suggest doing a
hand-written assembly routine, if I ever saw one...

>>>>>Of course Amazon, Yahoo and Ebay and most banks are
>>>>>kind of obsessed with them too, even if they don't know it.
>>>>
>>>>I think you would find that bignum operations are a small part of the
>>>>load on e-commerce servers.
>>>
>>>According to a paper by Intel, widening multiply accounts for something like
>>>30% of the load on typical e-commerce transactions (typing in your credit card
>>>over the net in a way that can't be snooped.)
>>
>>Reference, please.

> It was in a presentation at the Intel Developer Forum in 1999 or 2000. I only
> have this presentation in print form.
>
>>"load on typical e-commerce transaction" != "load on e-commerce server".

> I meant the server. Clients have cycles to burn, obviously the client
> performance doesn't matter on anything less than Half-life 2.

The question remains: how much time is your typical e-commerce server
involved in an actual transaction? Howe much transactions per second can
a machine handle now? I would suppose that most of the time spent in a
transaction is actually a database lookup at a creditcard company, not a
powermod. The frontend webserver is just waiting for the bank I think.
But these are just half-educated guesses.

>>If the transaction is simply setup session/send credit-card
>>information/close session, this could be right. However, a jiffy ago we
>>were talking SSL.
>>
>>
>>>One single assembly instruction (one *bundle* on Itanium) holds a whole server
>> > down for 30% of its computation,
>>
>>Again, you're equating server load with transaction load.

> Uhh ... both sides have to do the bignum operation.

I don't mean "client load" when I write "transaction load", I'm still
strictly speaking about the server. I could be convinced that the amount
of time spent in powermod for a 1-shot transaction could be as high as
30%, but I'd be hard-pressed to believe a front-end webserver is busy
for more than 10% doing actual transactions. I think the latency of an
e-commerce transaction is mostly caused by frontend<->bank
communication, and intra-bank database lookup. But I cannot back this up.

> You have to do it both
> ways because of man-in-the-middle attacks. Server load is what we are
> concerned with here, obviously (Itanium is *not* a client platform.)
>
>
>>>>Hang on, are we talking about "overflow" or "carry" here? These are two
>>>>different things with signed numbers.
>>>>
>>>>What happens if a is signed and b is unsigned?
>>
>>>My intend was for the operation to follow the semantics of the x86 ADC assembly
>>>instruction.
>>
>>Fun thing is: it handles both signed and unsigned numbers. Not-so-funny
>>is the fact that the x86 supports (as do most microprocessors) both an
>>overflow flag and a carry flag. So, armed with this, please elaborate on
>>the meaning.
>
>
> Yes, but I never mentioned/introduced overflow. I only considered carry. For
> bignum implementation, OF is not relevant. Only the CF is.

But for signed numbers, carry is almost meaningless. So what remains of
the semantics in this case?

>>>The point is that this instruction is known to be proper for
>>>doing correct bignum additions.
>>
>>It sure is... There are libraries containing hand-written assembly that
>>do fine :-)

> Go look at the original purpose of C again. Its supposed to be a portable
> assembler. This is a job for C.

I would usually agree on statements like this, but here's an exception.
I still have trouble envisioning carry semantics.

>>>>>- var is set to the result of the addition; the remainder if a carry occurs.
>>>>
>>>>What happens if the signedness of var, a, and b are not equal?
>>
>>>It just behaves like the ADC x86 assembly instruction, the details of which I
>>>will not regurgitate here.
>>
>>So on adding a signed plus unsigned.... The carry gets a value "as if"
>>the signed value was actually unsigned?

> Yes. Note that x86 does not have a version of ADC that considers the sign of
> its operands in any special way that is reflected in the CF.

Of course, but you have to know whether your operands are signed or
unsigned to see whether the CF or the OF is the important flag.

>>[...] On adding two signed numbers,
>>the carry gets a value "as if" both numbers were unsigned (instead of
>>the much more useful "overflow" indicator)? This looks like badly
>>designed semantics.

> It might to you, but the carry is not related to the sign of the operands.
> (Your understanding of x86 seems to be shakey.)

My x86 is not too strong, but I am quite well-versed in 6502, 68k and
PowerPC, which enables me to think about these things. They all share
carry and overflow bits in their designs, with little difference. After
performing an add-with-carry, both CF and OF are set (although the V
flag may not be reset, as in the 6502), but the CF generally does not
provide useful information when adding two numbers that are signed. So I
don't see how

c +< v = a + b

would provide useful information in c, when both a and b are signed, if
it is to copy the carry status.

>>>>What happens if the bit-widths of var, a, and b are not equal?
>>
>>>The bit-widths would be converted as if the (a + b) operation were happening in
>>>isolation, to match C language semantics.
>>
>>Ok, so if either is signed, they will both be signed,

> No ... that is not the rule used in C. unsigned supersedes signed.

Ok. That just leaves the case of two signed values, then.

I'm still wondering about the high_order_value() and low_order_value()
semantics I mentioned in my previous post, actually the part which I was
most curious about.

About the "billions of dollars" cost: I've snipped that part if you
don't mind. I like the technical issues much better :-) Let's agree that
there's a lot of money at stake.

Best regards,

   Sidney



Relevant Pages

  • Re: Real Time programs
    ... The abstract machine in the C standard, which is topical here, is ... time OS such as ThreadX. ... much different than programming a standard C program. ... Take a look at a good multithreading book such as ...
    (comp.lang.c)
  • Re: Portability: Harmony between PC and microcontroller
    ... int is the natural integer type for the system. ... You are, perhaps unintentionally, paraphrasing the standard in a way ... One of the things that you might not realize is that the C programming ... In the real world, most embedded systems have more complex jobs to do, ...
    (comp.lang.c)
  • Re: Sequence points
    ... They have been in the Standard since the Standard first appeared in 1989, ... you still don't understand sequence points. ... in areas outside of programming. ... programmers are in fact unequal to the demands of assembler language, ...
    (comp.programming)
  • Re: Code Review - is this code shit
    ... Good even though it's not in the Holy Standard. ... That is the stupidest analogy for a programming language I've ever ... A fortiori a program or a language is none of these things. ... The original message has the space there. ...
    (comp.lang.c)
  • RfD - Object Extensions
    ... While there is general agreement that Object-Oriented Programming (OOP) ... Forth currently has no standard extension for this. ...
    (comp.lang.forth)