A C showstopper

D

Dik T. Winter

> However, in a multithread environment where strings are passed by
> reference (that is, their address is passed by value), whenever you
> evaluate snprintf to do your own sprintf, the target strings could
> change unless you call them inside a lock.

If a string is passed the string can be modified during the operations of
snprintf changing the semantics, because now it is indeterminate what is
actually printed and whether printing will ever terminate. If you are
bothered that strings can change you have to lock anyhow before the printing
process starts.
> If a function is passed as a parameter, things will be worse.

How do you pass a function to snprintf and family?
> You're the C expert. If the function is passed in the call it is
> evaluated, its value is stacked, and there's no problem. But isn't it
> also possible to pass the address of the function, and "dereference"
> this inside mySprintf?

No, unless you have a mySprintf that is pretty unlike the remainder of
the print-family.
> The solution is to ignore snprintf and instead call sprintf for each
> parameter of yourSprintf() function, using varargs and testing strings
> to see if they'll blow your stack.

How do you do that if the string can change during the processing?
 
C

Charlton Wilbur

troll> Because working people, in modern capitalism, can never feel
troll> they are "experienced", there's little point in my repeating
troll> that I've had thirty years of experience.

It's more that there's little point in your repeating that you have
thirty years of experience when you have clearly learned so little.

Charlton
 
C

Chris M. Thomasson

[...]
However, in a multithread environment where strings are passed by
reference (that is, their address is passed by value), whenever you
evaluate snprintf to do your own sprintf, the target strings could
change unless you call them inside a lock. This lock will pin these
strings down for an unpredictable length of time, and this may create
problems in multithread applications that depend on locks using a
constant time.

FWIW, there ways to use shared strings without any locking whatsoever. One
simple example
is a simple COW-based solution to the classic reader/writer problem. That is
a reader thread can take a reference to a shared string without worry of
interference form writers such that they can read the string without
synchronization. I can do this with 100% lock-based or lock-free scheme,
simple pseudo-code for lock-based:


assume 32-bit system with DWCAS (e.g., IA-32)...
__________________________________________________________________
struct string {
char const* buffer;
atomic_word32 inner;
size_t size;
};


struct string_ref {
struct string* string;
atomic_word32 outer;
};


#define STRING_REF_INIT { NULL }




typedef char static_assert
[
sizeof(struct string_ref) == 64 / CHAR_BIT ? 1 : -1
];




struct string*
string_create(size_t size)
{
struct string* const self = malloc(sizeof(*self) + size + 1);

if (self) {
char* buffer = (char*)(self + 1);

buffer[0] = '\0';
self->inner = 0;
self->size = size;
self->buffer = buffer;
}

return self;
}


struct string*
string_acquire(struct string_ref* const self)
{
struct string_ref cmp, xchg;

cmp = *self;

do
{
xchg.string = cmp.string;
xchg.outer = cmp.outer + 1;

} while (! ATOMIC_DWCAS(self, &cmp, &xchg));

return cmp.string;
}


void
string_release(struct string* const self)
{
if (ATOMIC_FAA(&self->inner, -1) == 1)
{
free(self);
}
}


void
string_relpace(struct string_ref* const self,
struct string* new_string)
{

struct string_ref cmp, xchg;

xchg.string = new_string;
xchg.outer = 0;

cmp = *self;

while (! ATOMIC_DWCAS(self, &cmp, &xchg));

if (cmp.string)
{
if (ATOMIC_FAA(&cmp.string->inner, cmp.outer) == -cmp.outer)
{
free(self);
}
}
}

__________________________________________________________________




BTW, it is assumed that `ATOMIC_DWCAS()' automatically updated the comparand
upon failure.
 
C

Chris M. Thomasson

Chris M. Thomasson said:
[...]
However, in a multithread environment where strings are passed by
reference (that is, their address is passed by value), whenever you
evaluate snprintf to do your own sprintf, the target strings could
change unless you call them inside a lock. This lock will pin these
strings down for an unpredictable length of time, and this may create
problems in multithread applications that depend on locks using a
constant time.

FWIW, there ways to use shared strings without any locking whatsoever. One
simple example
is a simple COW-based solution to the classic reader/writer problem. That
is a reader thread can take a reference to a shared string without worry
of interference form writers such that they can read the string without
synchronization. I can do this with 100% lock-based or lock-free scheme,
simple pseudo-code for lock-based:

Ummm, pseudo-code for lock-free of course!


Yikes!



assume 32-bit system with DWCAS (e.g., IA-32)...
__________________________________________________________________ [...]
__________________________________________________________________
 
F

Flash Gordon

Chris said:
Chris M. Thomasson said:
[...]
However, in a multithread environment where strings are passed by
reference (that is, their address is passed by value), whenever you
evaluate snprintf to do your own sprintf, the target strings could
change unless you call them inside a lock. This lock will pin these
strings down for an unpredictable length of time, and this may create
problems in multithread applications that depend on locks using a
constant time.

FWIW, there ways to use shared strings without any locking whatsoever.
One simple example
is a simple COW-based solution to the classic reader/writer problem.
That is a reader thread can take a reference to a shared string
without worry of interference form writers such that they can read the
string without synchronization. I can do this with 100% lock-based or
lock-free scheme, simple pseudo-code for lock-based:

Ummm, pseudo-code for lock-free of course!


Yikes!

Ah, but it doesn't deal with the badly behaved thread that writes to a
string after it has "passed the reference" ;-)

I agree it's a good way of solving the higher level problem, and closer
to what I've done in assembler.

It all boils down to one way or another having to assure that one thread
won't write to the string while the other is reading from it, and it is
the same problem whatever language you are using. I didn't expect the
person I was originally replying to would understand that.
 
S

spinoza1111

Chris said:
Chris M. Thomasson said:
[...]
However, in a multithread environment where strings are passed by
reference (that is, their address is passed by value), whenever you
evaluate snprintf to do your own sprintf, the target strings could
change unless you call them inside a lock. This lock will pin these
strings down for an unpredictable length of time, and this may create
problems in multithread applications that depend on locks using a
constant time.
FWIW, there ways to use shared strings without any locking whatsoever.
One simple example
is a simple COW-based solution to the classic reader/writer problem.
That is a reader thread can take a reference to a shared string
without worry of interference form writers such that they can read the
string without synchronization. I can do this with 100% lock-based or
lock-free scheme, simple pseudo-code for lock-based:
Ummm, pseudo-code for lock-free of course!

Ah, but it doesn't deal with the badly behaved thread that writes to a
string after it has "passed the reference" ;-)

I agree it's a good way of solving the higher level problem, and closer
to what I've done in assembler.

It all boils down to one way or another having to assure that one thread
won't write to the string while the other is reading from it, and it is
the same problem whatever language you are using. I didn't expect the
person I was originally replying to would understand that.

As most of you should have known, but either didn't, or couldn't
express because you'd rather waste my time in the politics of vanity &
personal destruction, the problem in "simulating" sprintf() with
multiple passes over the format string is NOT restricted to multi-
thread applications where, as even the Flash here knows, you need to
lock the strings used.

I have been finishing student reports: this, and disgust with the
personalities here, caused my to stay away for a while. But today it
took me a half an hour to write and debug this code, which shows how
to break multipass sprintf().

#include <stdio.H>
int j;
int testFunction()
{
j = -j;
return j;
}

int main()
{
j = 1;
printf("Test function pointer: ");
printf("%d %d\n", (*(&(testFunction)))(), (*(&(testFunction)))());
return 0;
}

While it is deterministic, just replace j=-j by a nondeterministic
random number call or any time dependent code. It shows that C's
values are not in all cases available to either a single or a
multipass sprintf() simulator by value on the stack. If the above is
simulated by a multipass sprintf, and the first testFunction call
fails, the output numbers will start with -1 instead of 1.

This is also evidence for the poor design of C, since 95% of the
language assures the programmer that parameters on the stack are his
personal fiefdom. But, it appears, in basic C running as .C with
Microsoft C++ express, I can break this.
 
S

spinoza1111

...
 > However, in a multithread environment where strings are passed by
 > reference (that is, their address is passed by value), whenever you
 > evaluate snprintf to do your own sprintf, the target strings could
 > change unless you call them inside a lock.

If a string is passed the string can be modified during the operations of
snprintf changing the semantics, because now it is indeterminate what is
actually printed and whether printing will ever terminate.  If you are
bothered that strings can change you have to lock anyhow before the printing
process starts.

 > If a function is passed as a parameter, things will be worse.

How do you pass a function to snprintf and family?

#include <stdio.H>
int j;
int testFunction()
{
j = -j;
return j;
}

int main()
{
j = 1;
printf("Test function pointer: ");
printf("%d %d\n", (*(&(testFunction)))(), (*(&(testFunction)))());
return 0;
}
 
S

spinoza1111

In

spinoza1111wrote:
See my reply to your other recent article regarding this header.



This doesn't pass a function to snprintf. It passes two int values to
printf.

I figured you wouldn't understand how to do the homework.

Do the homework, Gomer. I've shown that two actual parameters can in
this admittedly rare case pass different values depending on whether
they are evaluated more than once, if they are procedure pointers. I'm
not a C "expert" (thank the Goddess in light of the twisted
personalities this "expertise" manufactures), so I may have missed
something. You haven't found it. Maybe Ben will.

The issue is whether a sprintf replacement can evaluate its parameters
more than once. I believe this example shows that it cannot, and must
therefore allocate a table holding all final values in addition to the
output area.
 
S

spinoza1111

In

spinoza1111wrote:




Implementations are under no obligation to recognise this header, and
gcc certainly doesn't. You meant:




Simpler:

printf("%d %d\n", testFunction(), testFunction());

This code will print either

Test function pointer: 1 -1

or

Test function pointer: -1 1

depending on the order of evaluation.

Correct. My example overelaborate, then. And furthermore, to argue
against my own example, it doesn't do anything that would not happen
in a single pass.

No matter how much indirection I add to the call of test print, C will
still execute it prior to the startup of my function.

Life sucks.

In a strong sense, you were also right: there really is no call by
reference in C in the sense of being able to delay an operation past
the point of function call.

You need, however, to work on your communication skills. Stop the
politics of personal destruction especially with regards to Jacob and
Herb, and stop making negative claims. Start by expounding your points
with some class. To learn this, read my writings.
 
D

Dennis \(Icarus\)

Richard Heathfield said:
In
spinoza1111 wrote:


No, it isn't evidence for the poor design of C, but it may be evidence
for your poor understanding of how to use it.

As if we'd need more evidence of that.

Dennis
 
S

spinoza1111

As if we'd need more evidence of that.

Dennis

It's off topic to use this newsgroup to compensate for your own low
self-esteem and your own feelings of incompetence, which in some cases
are well deserved in view of the low productivity of anglophone
programmers. The matter has been settled: Heathfield is right, but is
incredibly bad as a teacher. I had to figure out that "call by value"
is just that in C. He could have said so, but doesn't know how to
express himself openly, being more concerned with his position than
the truth.

I am accomplishing my goal here, which is appropriate: I am relearning
and learning C, because like you I don't at this time give a flying
**** about the opinions of fools.

Stop posting off-topic and offensive material.
 
D

Dik T. Winter

> Do the homework, Gomer. I've shown that two actual parameters can in
> this admittedly rare case pass different values depending on whether
> they are evaluated more than once, if they are procedure pointers.

You are wrong. What you wrote is similar to:
printf("%d %d\n", i++, i++);

It is not about passing procedure pointers, it is about what order the
parameters to a function are evaluated. Moreover, your syntax was
extraordinarily complex. Try the following:
int y = 1;
int f() { y = 1 - y; return y;}
int main(void) {
printf("%d %d\n", f(), f());
}
the result depends on whether arguments are evaluated left to right or
right to left, and so is not defined by the C standard.
 
F

Flash Gordon

spinoza1111 said:
Chris said:
[...]
However, in a multithread environment where strings are passed by
reference (that is, their address is passed by value), whenever you
evaluate snprintf to do your own sprintf, the target strings could
change unless you call them inside a lock. This lock will pin these
strings down for an unpredictable length of time, and this may create
problems in multithread applications that depend on locks using a
constant time.
FWIW, there ways to use shared strings without any locking whatsoever.
One simple example
is a simple COW-based solution to the classic reader/writer problem.
That is a reader thread can take a reference to a shared string
without worry of interference form writers such that they can read the
string without synchronization. I can do this with 100% lock-based or
lock-free scheme, simple pseudo-code for lock-based:
Ummm, pseudo-code for lock-free of course!
Yikes!
Ah, but it doesn't deal with the badly behaved thread that writes to a
string after it has "passed the reference" ;-)

I agree it's a good way of solving the higher level problem, and closer
to what I've done in assembler.

It all boils down to one way or another having to assure that one thread
won't write to the string while the other is reading from it, and it is
the same problem whatever language you are using. I didn't expect the
person I was originally replying to would understand that.

As most of you should have known, but either didn't, or couldn't
express

Chris's post was clear and showed excellent knowledge of the issues and
a lot more knowledge than me in how to deal with it.
because you'd rather waste my time in the politics of vanity &
personal destruction,

There was none of that in several of the posts.
the problem in "simulating" sprintf() with
multiple passes over the format string is NOT restricted to multi-
thread applications where, as even the Flash here knows, you need to
lock the strings used.

As Chris pointed out in his excellent post you do not need locks if you
use another appropriate strategy. I merely pointed out that it relies on
people actually following the agreed upon design strategy.

I might have pointed out how you can hit problems in non-threaded code,
but if you think your idea below matches any problems I might have
mentioned then you are very mistaken. It is signals, memory-mapped
devices, dual-port RAM (with something on the other side of it) and the
like that give you problems in non-threaded code, and Chris's solution
seems fine for all of those.
I have been finishing student reports: this, and disgust with the
personalities here, caused my to stay away for a while. But today it
took me a half an hour to write and debug this code, which shows how
to break multipass sprintf().

Half an hour? How could it possibly take that long?
#include <stdio.H>
int j;
int testFunction()
{
j = -j;
return j;
}

int main()
{
j = 1;
printf("Test function pointer: ");
printf("%d %d\n", (*(&(testFunction)))(), (*(&(testFunction)))());
return 0;
}

Others have pointed out why this does not show any of the problems that
were being discussed.

This is also evidence for the poor design of C,
Nope.

since 95% of the
language assures the programmer that parameters on the stack are his
personal fiefdom.

Local variables, including formal parameters initialised from arguments,
are like that in C (although not necessarily on a stack). This has
already been explained.
But, it appears, in basic C running as .C with
Microsoft C++ express, I can break this.

Appearances can be deceptive, although in this case it does not even
give the appearance of what you claim.

Oh, and think about the possibilities in a language which allowed both
calls to run in parallel... such a language woud be very useful if used
with care.
 
C

Chris M. Thomasson

Flash Gordon said:
spinoza1111 said:
Chris M. Thomasson wrote:
[...]
However, in a multithread environment where strings are passed by
reference (that is, their address is passed by value), whenever you
evaluate snprintf to do your own sprintf, the target strings could
change unless you call them inside a lock. This lock will pin these
strings down for an unpredictable length of time, and this may create
problems in multithread applications that depend on locks using a
constant time.
FWIW, there ways to use shared strings without any locking whatsoever.
One simple example
is a simple COW-based solution to the classic reader/writer problem.
That is a reader thread can take a reference to a shared string
without worry of interference form writers such that they can read the
string without synchronization. I can do this with 100% lock-based or
lock-free scheme, simple pseudo-code for lock-based:
Ummm, pseudo-code for lock-free of course!
Yikes!
Ah, but it doesn't deal with the badly behaved thread that writes to a
string after it has "passed the reference" ;-)

I agree it's a good way of solving the higher level problem, and closer
to what I've done in assembler.

It all boils down to one way or another having to assure that one thread
won't write to the string while the other is reading from it, and it is
the same problem whatever language you are using. I didn't expect the
person I was originally replying to would understand that.

As most of you should have known, but either didn't, or couldn't
express

Chris's post was clear and showed excellent knowledge of the issues and a
lot more knowledge than me in how to deal with it.
[...]

I need to show how the memory barriers could look, and then show some
pseudo-code on how to use it, I also made a typo in the `struct string'
data-structure. I made `string::buffer' constant, it should be mutable by
writer threads when it's quiescent, more on that later:
________________________________________________________________________
struct string {
/*

`buffer' is immutable when it's in a non-quiescent state,
and mutable when it is in a quiescent state.

*/

char* buffer;

atomic_word32 inner;
size_t size;
};




struct string_ref {
struct string* string;
atomic_word32 outer;
};


#define STRING_REF_INIT { NULL }




typedef char static_assert
[
sizeof(struct string_ref) == 64 / CHAR_BIT ? 1 : -1
];




struct string*
string_create(size_t size)
{
struct string* const self = malloc(sizeof(*self) + size + 1);

if (self) {
char* buffer = (char*)(self + 1);

buffer[0] = '\0';
self->inner = 0;
self->size = size;
self->buffer = buffer;
}

return self;
}


void
string_destroy(struct string* const self)
{
free(self);
}


void
string_system_destroy(struct string* const self)
{
MEMBAR_ACQUIRE();
string_destroy(self);
}


struct string*
string_acquire(struct string_ref* const self)
{
struct string_ref cmp, xchg;

cmp = *self;

do
{
xchg.string = cmp.string;
xchg.outer = cmp.outer + 1;

} while (! ATOMIC_DWCAS_ACQUIRE(self, &cmp, &xchg));

return cmp.string;
}


void
string_release(struct string* const self)
{
if (ATOMIC_FAA_RELEASE(&self->inner, -1) == 1)
{
string_system_destroy(self);
}
}


void
string_relpace(struct string_ref* const self,
struct string* new_string)
{
struct string_ref cmp, xchg;

xchg.string = new_string;
xchg.outer = 0;

cmp = *self;

while (! ATOMIC_DWCAS_ACQUIRE(self, &cmp, &xchg));

if (cmp.string)
{
if (ATOMIC_FAA_RELEASE(&cmp.string->inner, cmp.outer) == -cmp.outer)
{
string_system_destroy(cmp.string);
}
}
}
________________________________________________________________________








Here is a simple usage example:
________________________________________________________________________
static struct string_ref g_dynamic_html = STRING_REF_INIT;




/* Writer threads */
void
dynamic_html_update(struct string* new_html)
{

/*

Atomically transfer the local `new_html' string to the
global `g_dynamic_html' string.

*/

string_replace(&g_dynamic_html, new_html);
}


/* Reader threads */
int
dynamic_html_read_and_process(void)
{
/*

Atomically acquire a reference to the global `g_dynamic_html'
string.

*/

struct string* html = string_acquire(&g_dynamic_html);

if (html)
{
/*

`html' is in a non-quiescent state, therefore it's
immutable. Parse it, process the contained data,
whatever.

*/

puts(html->buffer);

string_release(html);
}
}




void foo()
{
struct string* html = string_create(html_get_size(...));

if (html)
{
/*

`html' is in a quiescent state, therefore it's mutable.

*/

html_build(html->buffer);


dynamic_html_update(html);

/*

`html' is in an indeterminate state wrt this thread.

*/
}
}
________________________________________________________________________




That should implement dynamic html which can be concurrently read from and
written to by multiple threads. After a reader thread acquires a reference,
it can read/parse the immutable string buffer directly. A writer simply
atomically swaps a new string in and merges the old strings differential
reference count (e.g., `string::inner' and `string_ref::eek:uter').




BTW, a quiescent state is defined as when the data-structure cannot, or will
not, be reached by any threads except the for the one that access to it. In
`foo()' the `html' string is only reachable by the currently executing
thread, therefore it's quiescent.

Non-quiescent is when a reader thread has a reference to the data-structure.
As soon as `foo()' passes the `html' string to `dynamic_html_update()' it
gets rendered into a non-quiescent state because it's now visible to, any
may have already been referenced by, reader threads.
 
S

spinoza1111

printf("%d %d\n", i++, i++); invokes undefined behavior.

The following code

#include <stdio.H>
int main()
{
int i;
i = 10;
printf("%d %d\n", i++, i++);
return 0;
}

when compiled using Microsoft C++ "in C mode" (with an input file with
type C) displays

11 10

and this is nonsense. The problem is that as of K & R, postincrement
was well-understood but it appears to me that the 99 standards twerps
really messed things up on behalf of compiler vendors and their
incompetent employees.

Perhaps I'm missing something. Can anyone

1. Reproduce this result
2. Explain it

As far as I can determine, 10 11 is the only sensible result since in
the "naive" world-wide understanding of C programmers, the post-
increment should NOT be delayed at the whim of the goddamn runtime
author. It should be completed, in the box, done prior to the
evaluation of the next i++ with no nonsense, and the code should print
10 11 and not 11 10.

But perhaps I am having an Homeric nod, or a senior moment.



Not in the vast majority of cases. Normal compilers will generate code
to fully evaluate i++ to the left of the rightmost comma.
 
S

spinoza1111

spinoza1111wrote:
Chris M. Thomasson wrote:
[...]
However, in a multithread environment where strings are passed by
reference (that is, their address is passed by value), whenever you
evaluate snprintf to do your own sprintf, the target strings could
change unless you call them inside a lock. This lock will pin these
strings down for an unpredictable length of time, and this may create
problems in multithread applications that depend on locks using a
constant time.
FWIW, there ways to use shared strings without any locking whatsoever.
One simple example
is a simple COW-based solution to the classic reader/writer problem.
That is a reader thread can take a reference to a shared string
without worry of interference form writers such that they can read the
string without synchronization. I can do this with 100% lock-based or
lock-free scheme, simple pseudo-code for lock-based:
Ummm, pseudo-code for lock-free of course!
Yikes!
Ah, but it doesn't deal with the badly behaved thread that writes to a
string after it has "passed the reference" ;-)
I agree it's a good way of solving the higher level problem, and closer
to what I've done in assembler.
It all boils down to one way or another having to assure that one thread
won't write to the string while the other is reading from it, and it is
the same problem whatever language you are using. I didn't expect the
person I was originally replying to would understand that.
As most of you should have known, but either didn't, or couldn't
express

Chris's post was clear and showed excellent knowledge of the issues and
a lot more knowledge than me in how to deal with it.
because you'd rather waste my time in the politics of vanity &
personal destruction,

There was none of that in several of the posts.
the problem in "simulating" sprintf() with
multiple passes over the format string is NOT restricted to multi-
thread applications where, as even the Flash here knows, you need to
lock the strings used.

As Chris pointed out in his excellent post you do not need locks if you
use another appropriate strategy. I merely pointed out that it relies on
people actually following the agreed upon design strategy.

I might have pointed out how you can hit problems in non-threaded code,
but if you think your idea below matches any problems I might have
mentioned then you are very mistaken. It is signals, memory-mapped
devices, dual-port RAM (with something on the other side of it) and the
like that give you problems in non-threaded code, and Chris's solution
seems fine for all of those.
I have been finishing student reports: this, and disgust with the
personalities here, caused my to stay away for a while. But today it
took me a half an hour to write and debug this code, which shows how
to break multipass sprintf().

Half an hour? How could it possibly take that long?

Bite me. Incompetents and fools measure competence by time.
Others have pointed out why this does not show any of the problems that
were being discussed.

No it doesn't.

No, it isn't. But as Galileo said, it still sucks.
Local variables, including formal parameters initialised from arguments,
are like that in C (although not necessarily on a stack). This has
already been explained.

Don't presume to explain a goddamn thing to me, Flash. I've had to
discover things on my own in my limited spare time because you creeps
can't explain things and are constantly trying to shore up your shaky
sense of self-worth.
 
C

Chris McDonald

spinoza1111 said:
The following code
#include <stdio.H>
int main()
{
int i;
i =3D 10;
printf("%d %d\n", i++, i++);
return 0;
}
when compiled using Microsoft C++ "in C mode" (with an input file with
type C) displays
and this is nonsense. The problem is that as of K & R, postincrement
was well-understood but it appears to me that the 99 standards twerps
really messed things up on behalf of compiler vendors and their
incompetent employees.


Do not assume that the parameters to printf() (or any function, for that
matter) are being evaluated, in time, from left-to-right. It appears
that on your system that they are being evaluated from right-to-left.

This has been pointed out to you before.
 
S

spinoza1111

...
 > Do the homework, Gomer. I've shown that two actual parameters can in
 > this admittedly rare case pass different values depending on whether
 > they are evaluated more than once, if they are procedure pointers.

You are wrong.  What you wrote is similar to:
   printf("%d %d\n", i++, i++);

It is not about passing procedure pointers, it is about what order the
parameters to a function are evaluated.  Moreover, your syntax was
extraordinarily complex.  Try the following:
   int y = 1;
   int f() { y = 1 - y; return y;}
   int main(void) {
      printf("%d %d\n", f(), f());
   }
the result depends on whether arguments are evaluated left to right or
right to left, and so is not defined by the C standard.

Thanks. But it appears to me that the C standard was a corporate
attempt to deprive the C community of its common understanding in C so
that the incompetent employees of vendors wouldn't have to do work and
could indeed be fired. There's too much that is "undefined". It sounds
very grave and wise to say that something is "undefined": it sounds
Nordic, as if the best the software guru could be would be Yoda or
some garden gnome groaning about knowledge forbidden to the happy
Folk.

As in Wagner (die Meistersinger and Tannhauser), master-ship has
changed its sign from the positive sign it had in the era of Algol 60,
when men thought to be clear, to a dark and negative sign.

Wagner, a nasty piece of work, experienced first hand how the
development of the means of production, far from empowering the
bourgeoisie, was subordinating it...to the means of production. Mozart
had to work for the Prince Bishop of Salzburg and suck up to Salieri
and the Emperor, but Beethoven used the primitive free market of the
turn of the 19th century to get paid for his work. By Wagner's time,
music publishers, using ever more elaborated means of production, were
calling the shots and once again composers were screwed unless they
themselves became businessmen-thugs, careful like Wagner to blame the
jews (the trolls) for their problems and not capitalism itself.

This is reflected in Wagner's strangely unamusing comic opera die
Meistersinger and also in Tannhauser, where winning song-contests
means affirming the values of a community rather than breaking new
ground, which Wagner in spite of himself sought to do. It's also
evident in the Ring and Parzival.

This material process has plainly happened in programming, for I am
old enough to remember a time when you could simply know, and make
predictions not falsified by corporate horseshit. It necessarily
involves the "politics of personal destruction" seen in the treatment
of protagonists in Tannhauser and Tristan: Herbert Schildt had like
Carthage to be destroyed because he, a sort of Last of the Mohicans,
had been an "individualist" who was "born to code". People who are
unable to make predictions about their own code because they are
incompetent cowards afraid of being wrong hit out at Herb because he
made predictions in the first place, not because those predictions
were wrong.

We can't have this anymore since Big Money is now involved for the
same reason we can spend billions on Afghanistan and bailouts and
nothing on education!

But what it means is that corporate gods have colonized people's minds
so as to make them corporate slaves who are more concerned with
sabotaging knowledge than with knowledge. The nasty (Wagnerian-nasty)
tone of these groups is the result.

Comma had a meaning before the standard. It meant "do this, and when
you are done, do this". This meaning should have been preserved. It
wasn't because of corporate incompetence and greed.
 
C

Chris Dollin

spinoza1111 said:
Thanks. But it appears to me that the C standard was a corporate
attempt to deprive the C community of its common understanding in C so
that the incompetent employees of vendors wouldn't have to do work and
could indeed be fired.

Don't be silly. It was an attempt -- a broadly successful attempt -- to
formalise C in a way that allowed existing widely-used implementations
to conform with only a reasonable amount of work.
There's too much that is "undefined".

Maybe so. But each bit of additional definedness requires work from
most of the implementors, and work in committee to make the choice.
None of the participants had unbounded resouces. "Undefined" means,
amonst other things, "not enough return on investment".
It sounds very grave and wise to say that something is "undefined":

No, it doesn't. Why on Earth do you think so?
As in Wagner (die Meistersinger and Tannhauser), master-ship has
changed its sign from the positive sign it had in the era of Algol 60,
when men thought to be clear, to a dark and negative sign.

This is all your own invention.

(fx:snip)
Comma had a meaning before the standard. It meant "do this, and when
you are done, do this".

The /comma operator/ had that meaning before that standard, as I recall.
The /comma separator/ -- which is what appears in argument lists -- didn't.

--
"Is there a reason this is written in iambic pentameter?" Marten,
/Questionable Content/

Hewlett-Packard Limited Cain Road, Bracknell, registered no:
registered office: Berks RG12 1HN 690597 England
 
B

Beej Jorgensen

spinoza1111 said:
printf("%d %d\n", i++, i++);

In C# (and Java) all the arguments are be executed sequentially
left-to-right, but in C they can be executed in any order, and not even
necessarily sequentially.

It's not any different than the order of operations in most expressions.
In C:

f() + g() + h()

evaluates the arguments in any order, unlike C# which goes
left-to-right.

# The order of evaluation of the function designator, the actual
# arguments, and subexpressions within the actual arguments is
# unspecified, but there is a sequence point before the actual call.

# J.1 Unspecified behavior
#
# The following are unspecified:

# The order in which subexpressions are evaluated and the order in which
# side effects take place, except as specified for the function-call (),
# &&, ||, ?:, and comma operators (6.5).

Personally, I like this sort of evaluation. And certainly C isn't the
only popular language to do it this way.

-Beej
 

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

No members online now.

Forum statistics

Threads
474,266
Messages
2,571,077
Members
48,772
Latest member
Backspace Studios

Latest Threads

Top