some well known stupidness in c99

F

fir

W dniu poniedziałek, 19 listopada 2012 17:42:18 UTC+1 użytkownik Eric Sosman napisał:
trace its explosive resurgence to feature creep. Let's at least
make it no worse, okay?

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.
 
J

James Kuyper

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
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?
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);
}

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.

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.
 
F

fir

W dniu poniedziałek, 19 listopada 2012 18:31:24 UTC+1 użytkownik James Kuyper napisał:
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?

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);

}



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.



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.

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 )
 
B

BartC

Eric Sosman said:
On 11/19/2012 9:25 AM, BartC 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?

As strchr() works now (I've just looked it up because I've never used it),
you pass it a char pointer (to a string), and it returns a char pointer (to
a char).

There's no particular advantage in using an enhanced pointer that also
contains a length, and the length of the result will be 1 if it's
successful.

But counted strings do have their uses: strlen() becomes trivial for a
start, also not requiring a zero terminator makes all sorts of things
possible. They wouldn't replace what's already in the language however. And
a lot of this can be done using existing language features (structs and
functions). It would just be tidier if 'fat' pointers were added to the
language.
 
F

fir

fputs(message, stderr);
why not fputs ? for aesthetic purposes
(as a programmer i work in beauty)

fputs is from library and without it one
can wrote useful programs without no api

but this bring it back to problem of arrays
and its sizes becouse of

(char* output, int lengthof_output) main(char* input, int lenghtof_input)
{

}

(char output[]) mian(char input[])
{

}

the second seem better in some ways
 
B

BartC

Eric Sosman said:
On 11/18/2012 7:04 PM, BartC wrote:

... which was James' point: "Any language that allows you
to do this does not support true separate compilation." If I
must recompile victim.c for each potential partner fileX.c, there
is no more separate compilation.

In your example, you were constructing two different programs: victim+file1,
or victim+file2.

You were deferring the selection of that companion file until 'link-time',
using a mechanism which I guess is not defined by the language.

In my example, I was suggesting that the selection was made at compile-time,
either victim+file1, or victim+file2 (with a mechanism not known to C
either). There isn't that much difference.

And in practice, changing a header file used by dozens of modules will
require recompilation of those modules; they are not that independent.
But what you're suggesting requires
re-compilation of a translation unit that has *not* changed, because
of something that's happened in some other translation unit.

Yes, but there is an advantage in doing so (being able to use less
indirection for example because of dealing with constants not extern
variables).

But this happens in C anyway: if I supply you with a library (a binary file)
and a header for it, you need to compile a program using my header.

If I release an update, and a new header, it would be advisable to recompile
your program with that header, even though nothing has changed in your
program. You can say that that header is part of the same translation unit,
but that is just words (my files containing export data also become part of
the same translation unit).
 
J

James Kuyper

W dniu poniedziałek, 19 listopada 2012 18:31:24 UTC+1 użytkownik James Kuyper napisał:

I would like to return whole string to system not just number (In general way maybe even any kind of data,

That's fine, but doesn't really answer my question - after you return
that string value, what do you want to have happen to it? If all you
want to do is return it, and you don't really care what happens to it
after it has been returned, you can achieve essentially the same result
in C by just typing:

exit("some string",0);

If you don't consider that an acceptable solution to your problem, that
means that you do care what happens to it after it has been returned,
and you should tell us what you want that to be.
However, in that case, you've got a serious problem: exit() marks the
beginning of the end of a C program; when it's done, "control returns to
the host environment". From that point onwards, the possibilities for
what can happen are determined by the host environment, and not by the C
standard.

The only thing the C standard requires is the ability to distinguish
successful and unsuccessful exit status. The committee decided on this
as a least-common denominator that would be implementable on almost
every known platform. If the host environment doesn't allow reporting an
exit status, a conforming implementation can simply ignore the argument
passed to exit(). On almost every system that does allow an exit status
to be reported, the distinction between unsuccessful and successful
results is sufficient. If, in some environment, more distinctions are
desired, the argument passed to exit() provides an interface that allows
such inherently unportable code to be written. If the host environment
requires more information than can be encoded in an 'int',
implementations of C targeting that environment would have to implement
an extension to C allowing the extra information to be reported.

Now, if you want to restrict your code to host environments which allow
the exit status to be a string, the current standard allows a fully
conforming implementation of C for such an environment to accept code
like the following:

exit((int)"some string");

This implies that 'int' must be big enough to reversibly store the
location of the string. If that would make 'int' too large to be useful
for other purposes, then an implementation targeting that environment
would have to provide some other method of specifying the string to be
returned. It also implies that if there is any char* pointer which
converts to an int value of 0, the string it points at (if any) must be
treated as having a successful exit status.

The key point is that the C standard is deliberately intended to be
implementable in a wide variety of host environments, including ones
which do NOT allow returning a string as an exit status. Therefore, if
you want the C standard to allow exit("some string"), it will need to
specify the required behavior of exit() in an implementation of C
targeted for such an environment. What do you think that specification
should be?

For reference, the current specification is:
"If the value of status is zero or EXIT_SUCCESS, an
implementation-defined form of the status successful termination is
returned. If the value of status is EXIT_FAILURE, an
implementation-defined form of the status unsuccessful termination is
returned. Otherwise the status returned is implementation-defined."
(7.22.4.4p5)
Any new specification will need to be backward compatible with the
current one, or it will have no chance of being accepted.
... 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 )

Well, since you brought it up, I'm using it as an example of how
seemingly "clever" "improvements" may have unforeseen consequences that
render them neither "clever", nor an "improvement".
 
J

James Kuyper

why not fputs ? for aesthetic purposes

I did use fputs(). Did you mean "Why fputs()?" - if so, you should
specify your preferred alternative. That hardly matters - it was just
meant as an example. If you do have a preferred alternative, use it.
 
E

Eric Sosman

In your example, you were constructing two different programs:
victim+file1, or victim+file2.
Exactly.

You were deferring the selection of that companion file until
'link-time', using a mechanism which I guess is not defined by the
language.

You could improve your guess by reading 5.1.1.1, 5.1.1.2p1
(point 8), 6.2.2, and so on.
In my example, I was suggesting that the selection was made at
compile-time, either victim+file1, or victim+file2 (with a mechanism not
known to C either). There isn't that much difference.

Exactly: You suggest "whole-program compilation" rather than
"separate compilation." C requires the latter.
And in practice, changing a header file used by dozens of modules will
require recompilation of those modules; they are not that independent.

That distinction's already been explained to you by me and
by others, but the explanations don't seem to have penetrated.
Yes, but there is an advantage in doing so (being able to use less
indirection for example because of dealing with constants not extern
variables).

Also the "advantage" of compiling each module once for use
in its unit test and again for use in the target program, with
the knowledge that in your model the two compilations are allowed
to produce drastically different code ...

Not sure where "indirection" comes into play.
But this happens in C anyway: if I supply you with a library (a binary
file) and a header for it, you need to compile a program using my header.

If I release an update, and a new header, it would be advisable to
recompile your program with that header, even though nothing has changed
in your program.

Yes: A change in the header is a change in your API, and
I must recompile. But if you release an update *without* a new
header -- you've fixed a bug or implemented a speedup, say, while
leaving the API unchanged -- in C-as-it-is I need not recompile,
while in C-as-you-suggest I must.
You can say that that header is part of the same
translation unit, but that is just words (my files containing export
data also become part of the same translation unit).

Nonsense. Do you claim that the Standard library is part
of the helloworld.c translation unit? (While reading 5.1.1.1,
you might want to take note of its definition of "translation
unit," and acquaint yourself with the way everybody else uses
"just words.")
 
F

fir

functions). It would just be tidier if 'fat' pointers were added to the
language.


probably some form of it would be needed
(maybe not fat pointers in general but
passing two values for any various
lenght array)

void clear(char table[])
{
for(int i=0; i<lengthof(table[]); i++)
{
table=0;
}
}

here table adr and table lenght would
be sent thru stack

if one want to optimize it he could do


void clear(char table[4096]) // for 4096-size arrays only
{
for(int i=0; i<lengthof(table[]); i++)
{
table=0;
}
}

and

void clear_table() // hardcoded
{
for(int i=0; i<lengthof(table[]); i++)
{
table=0;
}
}
 
J

James Kuyper

In your example, you were constructing two different programs: victim+file1,
or victim+file2.

You were deferring the selection of that companion file until 'link-time',
using a mechanism which I guess is not defined by the language.

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:
/* file1.c */
const int table_max = 100;

/* file2.c */
const int table_max = 200;

/* victim.c */
extern const int table_max;

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.
In my example, I was suggesting that the selection was made at compile-time,
either victim+file1, or victim+file2 (with a mechanism not known to C
either). There isn't that much difference.

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.
 
G

Greg Martin

W dniu poniedziałek, 19 listopada 2012 18:31:24 UTC+1 użytkownik James Kuyper napisał:

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 with your version of clever is that someone else's involves
using numeric return values to signal to the operating system success or
failure. This allows the chaining of applications as filters. If your
concern is being able to signal to a user the reason for exiting I think
that fprintf(stderr, "My reason") is at least as clever and allows the
user to choose where the error message should go and the operating
system can still determine whether processing in the chain should continue.

While OS and error logs aren't really C language issues they are a
rationale.
 
F

fir

W dniu poniedziałek, 19 listopada 2012 20:10:29 UTC+1 użytkownik Greg Martin napisał:
The problem with your version of clever is that someone else's involves
using numeric return values to signal to the operating system success or
failure. This allows the chaining of applications as filters. If your
concern is being able to signal to a user the reason for exiting I think
that fprintf(stderr, "My reason") is at least as clever and allows the
user to choose where the error message should go and the operating
system can still determine whether processing in the chain should continue.

While OS and error logs aren't really C language issues they are a
rationale.


(answer also to James Kuyper couse it is about the same thing) I just thinkthat returning a
string (or possibly maybe even accepting any binary data thru input and output) will be
better and more informative. OS could do
everything he wants, possibly print it out
in console or send it as an input to other c program (it is much unix like in good way)
It is good idea imo.

for example i would like much more return an
"could not find SSE processor" "OPENGL card not found" "SUCCES" "Compilation ok" "20:21:22 12-11-2012" or such like, than -1 or 0, 1, or 13 exit codes
 
J

James Kuyper

W dniu poniedziałek, 19 listopada 2012 20:10:29 UTC+1 użytkownik Greg Martin napisał: ....
(answer also to James Kuyper couse it is about the same thing) I just think that returning a
string (or possibly maybe even accepting any binary data thru input and output) will be
better and more informative. OS could do
everything he wants, ...

I don't want it to do anything. What do YOU want? It's your idea, and if
you're going to agitate for the idea to become reality, you're going to
have to specify what you think should happen - even when implementing C
for a platform which is incompatible with what you'd prefer to have
happen (which is virtually every platform I've ever heard of).
... possibly print it out
in console or send it as an input to other c program (it is much unix like in good way)

Not really. The Unix way is to have a 16-bit status code; 8 bits are the
lowest 8 bits of the value passed to exit(). POSIX reserves many of
those values for specific meanings, some of which should only be used by
the operating system, and leaves the rest available to the user. The
highest 8 bits identify the signal, if any, that caused the program to
terminate. That description might be inaccurate or out-of-date; I don't
ordinarily have any reason to worry about anything other than 0,
EXIT_SUCCESS, and EXIT_FAILURE. The unix way is to send textual outputs
to stderr, not the status code.
It is good idea imo.

The point is - what do you think should be the result when exit("some
string") is executed on an operating system where they disagree with you
about whether that's a good idea? I'm only familiar with a few operating
systems, but every one I've ever used has been incompatible with your
concept.
for example i would like much more return an
"could not find SSE processor" "OPENGL card not found" "SUCCES" "Compilation ok" "20:21:22 12-11-2012" or such like, than -1 or 0, 1, or 13 exit codes

Why is it better to put that in the exit status rather than stderr?
That's what stderr is for. It's not what the exit status is for.
 
K

Keith Thompson

James Kuyper said:
On 11/19/2012 12:42 PM, fir wrote: [...]
I would like to return whole string to system not just number (In
general way maybe even any kind of data,

That's fine, but doesn't really answer my question - after you return
that string value, what do you want to have happen to it? If all you
want to do is return it, and you don't really care what happens to it
after it has been returned, you can achieve essentially the same result
in C by just typing:

exit("some string",0);

I think you mean:

exit(("some string", 0));

Incidentally, I think the Plan9 environment does use strings rather than
integers as exit "codes":

http://swtch.com/plan9port/man/man3/exits.html

(Plan9 uses a non-conforming dialect of C.)

[...]
 
G

Greg Martin

W dniu poniedziałek, 19 listopada 2012 20:10:29 UTC+1 użytkownik Greg Martin napisał:


(answer also to James Kuyper couse it is about the same thing) I just think that returning a
string (or possibly maybe even accepting any binary data thru input and output) will be
better and more informative. OS could do
everything he wants, possibly print it out
in console or send it as an input to other c program (it is much unix like in good way)
It is good idea imo.

for example i would like much more return an
"could not find SSE processor" "OPENGL card not found" "SUCCES" "Compilation ok" "20:21:22 12-11-2012" or such like, than -1 or 0, 1, or 13 exit codes






(answer also to James Kuyper couse it is about the same thing) I just think that returning a
string (or possibly maybe even accepting any binary data thru input and output) will be
better and more informative. OS could do
everything he wants, possibly print it out
in console or send it as an input to other c program (it is much unix like in good way)
It is good idea imo.

for example i would like much more return an
"could not find SSE processor" "OPENGL card not found" "SUCCES"
"Compilation ok" "20:21:22 12-11-2012" or such like, than -1 or 0, 1, or
13 exit codes
The UNIX way is to return an numeric value upon exit, send text to
stderr for the reason for the error and stdout is the mechanism for
passing data between piped programs. exit(0) in Linux gas assembler
basically looks like this :
movl $1, %eax
movl $0, %ebx
int $0x80

If you want the exit you've described then in pseudocode you need
something like:
my_exit (str)
print_to_stderr str
return map_to_error_code (str)
 
J

James Kuyper

James Kuyper said:
On 11/19/2012 12:42 PM, fir wrote: [...]
I would like to return whole string to system not just number
(In general way maybe even any kind of data,

That's fine, but doesn't really answer my question - after you
return that string value, what do you want to have happen to it? If
all you want to do is return it, and you don't really care what
happens to it after it has been returned, you can achieve
essentially the same result in C by just typing:

exit("some string",0);

I think you mean:

exit(("some string", 0));

Yes. Ugh.
Incidentally, I think the Plan9 environment does use strings rather
than integers as exit "codes":

http://swtch.com/plan9port/man/man3/exits.html

(Plan9 uses a non-conforming dialect of C.)

And it provides it's own answers to the questions I've been trying to
get fir to answer about his suggestion:
Because of limitations of Unix, the exit status of a process can only
be an 8-bit integer. Exits and _exits treat null or empty exit status
as exit code 0 and call exitcode to translate any other string into
an exit code. By default, the library provides an exitcode that maps
all messages to 1. Applications may find it useful to provide their
own implementations of exitcode.

Implementing exitcode() sounds more complicated than what fir wants to do.
 
E

Eric Sosman

[...]
(Plan9 uses a non-conforming dialect of C.)

And it provides it's own answers to the questions I've been trying to
get fir to answer about his suggestion:
Because of limitations of Unix, the exit status of a process can only
be an 8-bit integer. Exits and _exits treat null or empty exit status
as exit code 0 and call exitcode to translate any other string into
an exit code. By default, the library provides an exitcode that maps
all messages to 1. Applications may find it useful to provide their
own implementations of exitcode.

Implementing exitcode() sounds more complicated than what fir wants to do.

int exitcode(const char *message) {
return message && *message;
}

(Even that much may be overkill, as Exits() and _exits() may
already have done the test.)
 
J

James Kuyper

[...]
(Plan9 uses a non-conforming dialect of C.)

And it provides it's own answers to the questions I've been trying to
get fir to answer about his suggestion:
Because of limitations of Unix, the exit status of a process can only
be an 8-bit integer. Exits and _exits treat null or empty exit status
as exit code 0 and call exitcode to translate any other string into
an exit code. By default, the library provides an exitcode that maps
all messages to 1. Applications may find it useful to provide their
own implementations of exitcode.

Implementing exitcode() sounds more complicated than what fir wants to do.

int exitcode(const char *message) {
return message && *message;
}

(Even that much may be overkill, as Exits() and _exits() may
already have done the test.)

That's what the default exitcode() does. If that behavior would be
acceptable, he'd have no need to provide his own implementation.

If fir could be convinced to acknowledge the need to specify what he
thinks exit("some string") should do on systems that do not allow the
exit status to be a string, I think he might want a less trivial
implementation of exitcode(), or some similar function. However, since
he has not yet acknowledged that need, I can't be certain.
 
B

BartC

Kenneth Brody said:
What language allows you to define the value in one module, and compile a
separate module, which makes no reference to the first module, and the
compiler "knows" what the constant is? (And, if you edit and recompile
the first module, changing the value of said constant, the second module
magically changes the constant's value?)

I gave an example of how it might work.

But I don't why you find this surprising: the same sort of magic is used now
in C, when changes in global variables are reflected across the whole
program.

And if you point out that this is a variable, whose value is only stored in
a single place, then I might respond that the variable's /address/ used to
access it, is a /constant/, used in a myriad places in a program, that all
magically end up referring to the same location!
 

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,574
Members
47,206
Latest member
Zenden

Latest Threads

Top