some well known stupidness in c99

G

glen herrmannsfeldt

(snip)
Well, yes. Mechanisms are the domain of implementers, they are outside
the scope of the C standard. Consider files containing the following
lines, among others:

Before there was C, there was Fortran and BLOCK DATA, which requires
a similar implementation. So, linkers would already know how to do
this even if implemented before C existed.

The OS/360 linker, for example, takes the first CSECT that it finds
if there are duplicates. That allows for the actual editing in the
name linkage editor. If you need to replace one CSECT in a previously
compiled and linked program, load the new one in, then INCLUDE the
old load module. The linkage editor keeps the new CSECT in place of
the old one with the same name, updates all the address constants,
and everything works.
The standard says the behavior is undefined if file1 and file2 are both
linked into the same program. Otherwise, if file1 and victim are linked
into a single strictly conforming program, the value of table_max in
that program must be 100. If file2 and victim are linked, it must be
200. The standard doesn't specify the mechanism used to achieve this,
but it does require that some mechanism be used to make it happen.
The difference is that C mandates the behavior we describe, regardless
of what mechanism is used to achieve it. To have the behavior occur at
compile time, as you described, file1.c or file2.c would have to be
#included into victim.c during the compilation phase, rather than linked
to it after compilation. As far as C is concerned, "victim.c + #included
file1.c" is one translation unit, and "victim.c + #included file2.c"
would be a different one.

Or a fancier linker than we usually have.

-- glen
 
G

glen herrmannsfeldt

(snip)
at least (when my attempt to had a lenghtof()
without fat pointers somewhat fails by now here)
i could done one important remark to my
own self (which i not noticed before):
c language can (and probably should) guard
the type safety between pointers-to-one and
pointers-to-many, it would straighten (type)
safety and wold also improve the expresiveness
of the code :/

But then why not consider pointers to length two
different from pointers to length three?

Is a pointer to a scalar that different from an
array of length one?

(I have used arrays of length one in Java programs where a C
scalar would have been used.)

-- glen
 
E

Eric Sosman

W dniu poniedziałek, 19 listopada 2012 18:31:24 UTC+1 użytkownik James
Kuyper napisał:
On 11/19/2012 12:06 PM, fir wrote:
W dniu poniedziałek, 19 listopada 2012 17:42:18 UTC+1 użytkownik
Eric Sosman napisał:
[...]
some improvements would be strngly velcome
for some, for example I am always mad when
i must exit(-1) or exit(13) instead of
exit("some string") For me cleaver improvements are nice.

Assume that the standard were changed to allow that - what would you
want it to do with the string? What should people do who don't want that
[...]
I would like to return whole string to system not just number (In
general way maybe even any kind of data, I was sayin that few week ago,
here I just used it as an argument that clever
improvements ale welcome - so there is point
of inventing and also talking about them )

The problem is, the operating system is expecting a number, not a
string. You can't have C return a string to the O/S if the O/S requires
a number.

Note that, in over 40 years, I have never worked on a computer where the
O/S was expecting something other than a plain old-fashioned integer as
the exit value.

I've used an O/S where the exit code was a group of three
or four values: a "severity," a "message ID," a "facility ID,"
and a few other oddments (my memory fades). Nonetheless, all
were packed into sub-fields of a 32-bit word, so the whole thing
could be (and was) treated as an integer, although perhaps not a
"plain old-fashioned" one. Struct with bit-fields, really.

(An infelicity of the particular coding was that the low-order
bit was 1 for "success" and 0 for "error or warning or something."
For quite a while, the system's shell-equivalent was blissfully
silent when a C program performed exit(1) -- Hey, that's a success
code, right? Meanwhile, programs that finished with exit(0) elicited
a message that they'd exited with a "warning" status! Eventually,
the vendor special-cased those values inside the C library.)

(Some of that vendor's products, by the way, are on display
at the Computer History Museum. That may be the only place you
can find them nowadays ...)
 
G

glen herrmannsfeldt

(snip, someone wrote)
When strchr() finds a character in a string, what "span" should
the returned pointer have? Should its limits cover the whole string,
just the tail from the start of the search, just the part searched,
the entire array containing the string, just the located character,
or what? You have to know what the caller intends to do with the
pointer before you can know what kind of pointer to return.

Pretty much has to be the whole string.

I am sure that there are many programs that strchr(s,'\n')
to find the end of a line, then index back from there.

One might check before using such returned value that it
wasn't before the start, but the program might already
know that.

As C doesn't allow mixing pointers to different objects, it should
be possible to make a legal implementation that keeps the length and
origin (or length before and after) for a pointer.

Note that the similar trick in Fortran doesn't allow one to go back.

REAL X(100)
CALL SUB(X(51))

the called subrouting is allowed to look at only the elements of X
from 51 to 100. (Yes this is part of the Fortran standard.)
While it will work in many implementations, the subroutine should not
try to reference array elements before 51.

-- glen
 
B

BartC

James Kuyper said:
On 11/19/2012 01:25 PM, BartC wrote:
Well, yes. Mechanisms are the domain of implementers, they are outside
the scope of the C standard. Consider files containing the following
lines, among others:


The standard says the behavior is undefined if file1 and file2 are both
linked into the same program.

(Actually, in the counter-example I gave, it's possible to have both
table_max constants at the same time! It looks like this:

import file1
import file2

println file1.table_max
println file2.table_max

Although it does need a qualifier to disambiguate the two. But this is
something is that is also quite handy.)
The difference is that C mandates the behavior we describe, regardless
of what mechanism is used to achieve it. To have the behavior occur at
compile time, as you described, file1.c or file2.c would have to be
#included into victim.c during the compilation phase, rather than linked
to it after compilation.

That of course is also possible. If victim.c and file1.c were originally one
file, then later split into two, you're saying the two files can no longer
share the same constants, at least not without putting the common values in
a third file, a common header, except that is often not practical (because
the values might depend on something in the body of file1.c).

However that is not necessary. Suppose file1.c contained the following:

#define abc 90215 /* global constant */

And you ran some program on file1.c which picked out defines that had a
'global constant' comment, and produced a file file1.h containing:

#define abc 90215

This file is then included in victim.c. You're now exporting a constant from
file1.c into victim.c - congratulations! See it wasn't that difficult, and
/you don't need file1.c at the point where victim.c is compiled/. Although
you have introduced an extra dependency which has to be borne in mind when
updating these files (but that's nothing new in C).

Of course such a mechanism is crude: it wouldn't work here for example:

int a[] = {10,20,30};
#define alength (sizeof(a)/sizeof(a[0])) /* global constant */

because '(sizeof(a)...' would be meaningless outside this module. You need a
cleverer utility, or be supported by the language, so that the output is
something like:

#define alength 3

Anyhow, I use this stuff and find it very convenient. If you don't want it
in C (and it's never going to happen anyway) I don't really care! I'm just
pointing out that it can be done, whatever excuses you keep coming up with
why it would never work...
 
B

BartC

Eric Sosman said:
On 11/19/2012 1:25 PM, BartC wrote:
Not sure where "indirection" comes into play.

By 'indirection' I mean having to use a variable instead of a constant. So I
can define:

int table[table_max];

instead of:

int* table=malloc(table_max*sizeof(int));

Or I might be able to write:

switch (a) {
case table_max:
....

etc. when table_max is defined in another module.

You can't deny these can be advantages.
 
G

glen herrmannsfeldt

James Kuyper said:
On 11/19/2012 12:06 PM, fir wrote:
(snip)
Assume that the standard were changed to allow that - what would you
want it to do with the string? What should people do who don't want that
to happen? Whether you like it or not, many existing operating systems
require that when programs exit, they pass to the operating system an
exit status of some kind. If you use exit("some string"), which exit
status should it pass to the operating system? If someone wanted to pass
a different exit status, how could they do that?

Fortran has both STOP (integer contant) and STOP (string constant)

The standard suggests, but doesn't require, that if the underlying
system requires an integer that it be zero.

Also, that the string or integer be printed to ERROR_UNIT.
Whatever it is you want that function to do, you can probably trivially
write your own function as a wrapper for exit(), and have it do whatever
it is that you want it to do:
void my_exit(const char*message)
{
fputs(message, stderr);
exit(EXIT_SUCCESS);
}

Unless C now has function overloading, such that one function can
take either and int or (char*) it would have to be done that way,
anyway.
That way, only your code has to work this way; people who want different
behavior when the program exits are free to write they're own exit wrappers.

But you could say that about half the features in the C standard,
including most of the standard library. The thing about having the
standard is that everyone doesn't have to reimplement them.
Note: there are only three values you can pass to exit() with behavior
that is defined by the C standard: EXIT_SUCCESS, EXIT_FAILURE, and 0.
The meanings of -1 or 13 can be different for different implementations
of C.

Especially interesting in the case of VMS.

-- glen
 
G

glen herrmannsfeldt

(snip)
The problem is, the operating system is expecting a number, not a string.
You can't have C return a string to the O/S if the O/S requires a number.
Note that, in over 40 years, I have never worked on a computer where the O/S
was expecting something other than a plain old-fashioned integer as the exit
value.

Even more, usually only eight bits. I believe that the OS/360 return
codes are eight bit integers, and still implemented in its decendants
through z/OS. For unix it is eight bits. I believe VMS is 16, but
haven't looked lately. VMS traditionally gives a message based on the
index into a table. If you start picking numbers, you might be
surprised.

OS/360 return codes are usually multiples of four. (Convenient for
use in a branch table or table of address constants.) for many
programs 4 is what would be called warning, 8 for error, 12 for
severe error, and 16 for something worse. (The inability to open
SYSPRINT (what others would call stdout) usually results in 16.)

I don't know how many bits Windows allows.

-- glen
 
E

Eric Sosman

By 'indirection' I mean having to use a variable instead of a constant.

'When I use a word,' Humpty Dumpty said, in rather a
scornful tone, 'it means just what I choose it to mean —
neither more nor less.'

'The question is,' said Alice, 'whether you can make words
mean so many different things.'

'The question is,' said Humpty Dumpty, 'which is to be
master — that's all.'
So I can define:

int table[table_max];

instead of:

int* table=malloc(table_max*sizeof(int));

In C99, or in C11 with VLA support, each of these is usable
wherever the other is, and neither is usable where the other is
not. So, what's the big hoo-haw? (By "hoo-haw," I of course
mean "glory.")
Or I might be able to write:

switch (a) {
case table_max:
...

etc. when table_max is defined in another module.

You can't deny these can be advantages.

Sure, I can.

extern const int table_max;
...
switch(a) {
case table_max: puts("Yes"); break;
case 1: puts("NO!"); break;
}

See the duplicate case label? No? Well, you can't deny that
it might *become* a duplicate case label with next week's edit
to some entirely different module. Once again, you've done
away with separate compilation.
 
E

Eric Sosman

Pretty much has to be the whole string.

What would happen with

char string[100] = "Hello, world";
char *p = strchr(string, ' ');
strcpy(p + 1, "my ragtime gal");

? If the span of `p' covers the thirteen characters of the
original string, should strcpy() fail because it tries to
deposit characters beyond that range? If so, I don't like
it -- and if not, what good is it?

I've never seen a fat-pointer proposal that dealt well
with managing the "span" in other than trivial circumstances.
 
G

glen herrmannsfeldt

(snip, someone wrote)
Sure, I can.
extern const int table_max;
...
switch(a) {
case table_max: puts("Yes"); break;
case 1: puts("NO!"); break;
}

There is no reason that this couldn't be done, but it isn't the
usual C switch. The switch in verilog allows it.
See the duplicate case label? No? Well, you can't deny that
it might *become* a duplicate case label with next week's edit
to some entirely different module. Once again, you've done
away with separate compilation.

I believe the verilog switch takes the first case that matches,
and where the case values can be run-time expressions. They usually
are constants, and it is probably better when they are.

-- glen
 
G

glen herrmannsfeldt

(snip, I wrote)
What would happen with

char string[100] = "Hello, world";
char *p = strchr(string, ' ');
strcpy(p + 1, "my ragtime gal");
? If the span of `p' covers the thirteen characters of the
original string, should strcpy() fail because it tries to
deposit characters beyond that range? If so, I don't like
it -- and if not, what good is it?

As I said, the whole string. So *p has to include the whole 100
characters of string, six before and 93 after.

It does help against going outside array bounds, including all
the attacks of public systems based on such attacks.
I've never seen a fat-pointer proposal that dealt well
with managing the "span" in other than trivial circumstances.

Not so hard to do if you don't mind the overhead of doing it.

-- glen
 
J

James Kuyper

On 11/19/2012 4:55 PM, BartC wrote: ....
So I can define:

int table[table_max];

instead of:

int* table=malloc(table_max*sizeof(int));

In C99, or in C11 with VLA support, each of these is usable
wherever the other is, and neither is usable where the other is
not.

Wherever? Even at file scope?
 
B

BartC

Eric Sosman said:
On 11/19/2012 4:55 PM, BartC wrote:
So I can define:

int table[table_max];

instead of:

int* table=malloc(table_max*sizeof(int));

In C99, or in C11 with VLA support, each of these is usable
wherever the other is, and neither is usable where the other is
not. So, what's the big hoo-haw? (By "hoo-haw," I of course
mean "glory.")

You really don't see that an array accessed by an offset in a data segment
might be better than one accessed via a pointer?
Sure, I can.

extern const int table_max;
...
switch(a) {
case table_max: puts("Yes"); break;
case 1: puts("NO!"); break;
}

See the duplicate case label? No?

Yes, actually I can see the possibility, because it would be bad practice to
mix named and explicit constants like this (even if the compiler will anyway
pick up the error).
Well, you can't deny that
it might *become* a duplicate case label with next week's edit
to some entirely different module. Once again, you've done
away with separate compilation.

How is the above example different from this:

#include <windows.h>

switch (a) {
case CBN_DBLCLICK: ...
case 1: ...

That might *also* become a duplicate label with next week's version of
windows.h. (Or substitute any header that you haven't written yourself.)
 
B

BartC

Eric Sosman said:
On 11/19/2012 4:48 PM, glen herrmannsfeldt wrote:
What would happen with

char string[100] = "Hello, world";
char *p = strchr(string, ' ');
strcpy(p + 1, "my ragtime gal");

? If the span of `p' covers the thirteen characters of the
original string, should strcpy() fail because it tries to
deposit characters beyond that range? If so, I don't like
it -- and if not, what good is it?

I've never seen a fat-pointer proposal that dealt well
with managing the "span" in other than trivial circumstances.

I've used 'fat-pointer'-like descriptors extensively to manage strings when
implementing dynamic languages. They work very well.

But they work well, despite having limited flexibility compared to C
string-handling. C needs that flexibility (to help implement those languages
for one thing, and for that it needs to be able to work behind the scenes).

So I don't think any proposal should do away with plain pointers and current
string handling; it should be in addition.
 
K

Keith Thompson

Eric Sosman said:
I've used an O/S where the exit code was a group of three
or four values: a "severity," a "message ID," a "facility ID,"
and a few other oddments (my memory fades). Nonetheless, all
were packed into sub-fields of a 32-bit word, so the whole thing
could be (and was) treated as an integer, although perhaps not a
"plain old-fashioned" one. Struct with bit-fields, really.

(An infelicity of the particular coding was that the low-order
bit was 1 for "success" and 0 for "error or warning or something."
For quite a while, the system's shell-equivalent was blissfully
silent when a C program performed exit(1) -- Hey, that's a success
code, right? Meanwhile, programs that finished with exit(0) elicited
a message that they'd exited with a "warning" status! Eventually,
the vendor special-cased those values inside the C library.)

Sounds like VMS, later renamed to OpenVMS.
(Some of that vendor's products, by the way, are on display
at the Computer History Museum. That may be the only place you
can find them nowadays ...)

I worked on production OpenVMS systems as recently as 1999.
I don't know whether they're still in use, but I suspect they are.
It's likely they've finished migrating from VAXes to Alpha systems
by now. (Qualcomm's OminTRACS, if you're curious.)
 
K

Keith Thompson

glen herrmannsfeldt said:
(snip, I wrote)
What would happen with

char string[100] = "Hello, world";
char *p = strchr(string, ' ');
strcpy(p + 1, "my ragtime gal");
? If the span of `p' covers the thirteen characters of the
original string, should strcpy() fail because it tries to
deposit characters beyond that range? If so, I don't like
it -- and if not, what good is it?

As I said, the whole string. So *p has to include the whole 100
characters of string, six before and 93 after.

A "string" is, by definition, "a contiguous sequence of characters
terminated by and including the first null character". The "whole
string" is just the 13 bytes from the 'H' to the terminating '\0'.
You mean the whole *array*.
Not so hard to do if you don't mind the overhead of doing it.

I'd expect any C fat pointer implementation to deal with whole array
objects and ignore any '\0' bytes that happen to be contained in them.
 
G

glen herrmannsfeldt

Keith Thompson said:
(snip, I wrote)
Pretty much has to be the whole string.
What would happen with

char string[100] = "Hello, world";
char *p = strchr(string, ' ');
strcpy(p + 1, "my ragtime gal");
? If the span of `p' covers the thirteen characters of the
original string, should strcpy() fail because it tries to
deposit characters beyond that range? If so, I don't like
it -- and if not, what good is it?
As I said, the whole string. So *p has to include the whole 100
characters of string, six before and 93 after.
A "string" is, by definition, "a contiguous sequence of characters
terminated by and including the first null character". The "whole
string" is just the 13 bytes from the 'H' to the terminating '\0'.
You mean the whole *array*.

OK, yes. The six characters before the ' ' are still part of the
"string", but yes the rest of the array, too.

-- glen
 
F

fir

W dniu wtorek, 20 listopada 2012 00:50:35 UTC+1 użytkownik Bart napisał:
On 11/19/2012 4:48 PM, glen herrmannsfeldt wrote:


What would happen with
char string[100] = "Hello, world";
char *p = strchr(string, ' ');
strcpy(p + 1, "my ragtime gal");

? If the span of `p' covers the thirteen characters of the
original string, should strcpy() fail because it tries to
deposit characters beyond that range? If so, I don't like
it -- and if not, what good is it?

I've never seen a fat-pointer proposal that dealt well
with managing the "span" in other than trivial circumstances.



I've used 'fat-pointer'-like descriptors extensively to manage strings when

implementing dynamic languages. They work very well.



But they work well, despite having limited flexibility compared to C

string-handling. C needs that flexibility (to help implement those languages

for one thing, and for that it needs to be able to work behind the scenes).



So I don't think any proposal should do away with plain pointers and current

string handling; it should be in addition.


As I said before the best option i see by now
is to send adres and length in such case of
array passing

void print(char text[])
{
for(int i=0; i<lengthof(text); i++)
put_char_on_console(text);
}

and reserve other syntax to pass only tha addr

void print(char* text)
{

}

also guard the type guarding between pointers-to-one and pointers-to-many(undefined how many)
(and for sure also to guard also pointers-to-four, pointers-to-five etc)

the question is how syntax to choose to distinguish between pointers-to-oneand pointers-to-many in such cases:

void print(char* text) //pointer to undefined many
{

}

void print(char(1)* text) //pointer to one ?
{

}
 

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,573
Members
47,205
Latest member
ElwoodDurh

Latest Threads

Top