some well known stupidness in c99

J

James Kuyper

In that case C doesn't have true separate compilation either, if it needs
header files to tell it something about the contents of separate modules.

The header files are compiled separately as part of each translation
unit. It's even possible, and in some contexts useful, to have them
compile differently in different translation units. They're basically
just a technique for getting identical text into different translation
units.
I'm sure that 'compile-time' means pretty much the same, ie. a value known
to the compiler.

The implications are quite different when the things that can be known
at compile time are different. A #defined constant in a shared header
file can be known at compile time in C (and could be different in
different translation units for the same header file, if set up
properly). The value of an object with external linkage that is defined
in some other translation unit cannot be known at compile time in C, and
cannot (with defined behavior at least) be different in different
translation units, no matter what fancy tricks you use. The closest
equivalents in your language works quite differently, and that changes
the implications of "compile time".
 
J

James Kuyper

On 11/18/2012 08:38 PM, Ian Collins wrote:
....
The one that really really bugged me was attempting to debug some code
that had a excess of #define constants was the inability of the debugger
to evaluate them.

Some debuggers handle that better. I was rather pleasantly surprised the
first time I accidentally made use of that feature.
 
J

James Kuyper

On 11/18/2012 08:38 PM, Ian Collins wrote:
....
The one that really really bugged me was attempting to debug some code
that had a excess of #define constants was the inability of the debugger
to evaluate them.

Some debuggers handle that better. I was rather pleasantly surprised the
first time I accidentally made use of that feature.
 
B

Ben Bacarisse

Another somewhat contrived example is:

#define X 42

void f( const int* p );

int main(void)
{
f(&X);
}

You can write f(&(int){X}); so that it will work no matter if X is a
macro, an enum name or an int object (const or otherwise).

I don't suggest this as an elegant solution, but simply as a solution
that might be useful if the situation arises in some large code base.
 
R

Richard Damon

....

Personally, I agree that it would be nice if C treated const definitions
with constant initializers the way C++ does, so that given

const int answer = 42;

answer would be a constant expression, and I would support such a
change in a future revision. Kenneth Brody pointed out a case where
such a change could break existing code:

===== file1.c

const int table_max = 100;

===== file2.c

extern const int table_max;

This could probably be worked around by making the definition introduce
a constant expression *and* a read-only object. Or, I suppose, the
commitee could decide that it's ok to break existing code in this case,
though that's probably unlikely.

But such a change would require some significant work to define its
behavior in *all* cases, followed by changes to all conforming C
implementations.

having a const int not generate an external global read only object
would be a big mistake in my opinion. One solution would be to use

static const int table_max = 100;

being static, the name only has scope for that translation unit, and the
compiler is allowed to omit the actual generation of the object by the
"as if" rule if it is not needed.

The other thing to note, is I believe that currently, multiple
definitions of a global in different translation units is not a
constraint violation, but undefined behavior, so the compiler would be
allowed (but not required) to make it work as expected, letting the
program compile, link, and run, and even not take up memory for the
value if not needed. Typically this would be done by making a "weak
definition" for the object, and letting the linker discard it if not
needed, or allow multiple definitions as needed.

It might be possible for a future standard to REQUIRE the compiler to
make this case work, but it might be hard to find a specification that
actually allowed the desired multiple definitions without also forcing
the compiler to accept as valid multiple definitions that are really
programming errors.

Another option might be to allow a construct like

extern const int table_max = 100;

to declare the value as a constant expression without allocating memory
for it, and require exactly one translation unit to have a definition like:

const int table_max;

to generate the memory location for any uses that might need it.
 
F

fir

W dniu niedziela, 18 listopada 2012 23:20:51 UTC+1 użytkownik Keith Thompson napisał:
your English is certainly better than my own nonexistent Polish.)

Mysle, ze to moze byc prawda, (but do not
matter).

May add some things about const and arrays:
(somewhat different topic and area than my simple 'lack od const int array handling is
unpleasant')

As to const imo in c 'const idea' may relate
to a couple of things,
1) solid constant value located in ram
2) immediate constant value defined in language but resolved as a bunch of immediate
values
3) some readonly-like modifier that can be
even applied and removed in runtime
4) maybe yet even other meanings (If one
would see some other I would like to read
about it)

The other 'think theme' is a c way of handling
array sizes and array lengths, which is in some
part nonexistant in c, In other part it is
existant and that c way is that that array
sizes are held by static, 'compiler space ' approach. So there is no tradition of
combining localized ram info about array
sizes with arrays

1) it is somewhat cleaver to do it on
compiler space level (c spirit)

2) if this (ram array size handling)
could be done it could be possibly
done in more automatic way - the array
length int should be possibly handled
by compiler, so it could be in a way
part of array info not free constant int
related to that

(but those are more elaborate topics,
I am working on it on the area of more far
c improvements)
 
F

fir

W dniu poniedziałek, 19 listopada 2012 10:21:10 UTC+1 użytkownik fir napisał:
The other 'think theme' is a c way of handling
array sizes and array lengths, which is in some
part nonexistant in c, In other part it is
existant and that c way is that that array
sizes are held by static, 'compiler space ' approach. So there is no tradition of
combining localized ram info about array
sizes with arrays



1) it is somewhat cleaver to do it on
compiler space level (c spirit)

2) if this (ram array size handling)
could be done it could be possibly
done in more automatic way - the array
length int should be possibly handled
by compiler, so it could be in a way
part of array info not free constant int
related to that



(but those are more elaborate topics,
I am working on it on the area of more far
c improvements)


(a want to add something)


In this citation above, indeed, it wass said how could it be done (but will write it more
explicit here maybe):

some five years ago I was thinking some
amount about fatpointers (pairs pointer length), (some dialect of c called cyclone has it as faras i remember)
one can also try to send size thru function
argument (as in K&R book AFAIR) but i see
there is a better aproach:

->

c lacks an lengthof() operator, it could be
done easily and also use efficiently (more
efficient than size passing)

Its value can be obtained in some cases
for free in static, compiler time approach
on the other cases it could be obtained from
this array length ram value handled by compiler
i was mentioning about before (thios could be
stored by compiler, for 100 arays it would be 100 stored longs, assigned inthe

int table[8866]; // internal lengthof_table assigned to 8866

moment and accesible by lengthof() operator or
such ways

it is reasonably ok idea I think but should also be under some more thinking yet

(fir)
 
B

BartC

James Kuyper said:
On 11/18/2012 08:36 PM, BartC wrote:

The header files are compiled separately as part of each translation
unit. It's even possible, and in some contexts useful, to have them
compile differently in different translation units. They're basically
just a technique for getting identical text into different translation
units.

I do the same; that 'import module' stuff just boils down to including a
file in the same way that C does it.

The difference is that I allow that file to be created automatically as part
of how the language works. If that feature wasn't available, I could write
that file by hand, or code it directly, just like you have to do in C.
Conversely, you could bolt-on some utility to C to construct certain headers
automatically, which I'm sure is already done (and as I've done with
function prototypes).

So, if I knew there was an array X in module B of length 10, I could write
this in module A:

#define XLEN 10

but I'd need to keep it up-to-date every time B changed. (Of course if the
sources to B were hidden, then I wouldn't know this unless the authors
explicitly made this known, via docs or via an include file (in which case I
might not need my #define).)

Effectively, we've managed to export a local array size, a compile-time
constant, from a module. We're arguing about the mechanisms for doing so
automatically.
The implications are quite different when the things that can be known
at compile time are different. A #defined constant in a shared header
file can be known at compile time in C (and could be different in
different translation units for the same header file, if set up
properly).

Yes, that's a feature of C that makes it so easy to compile! (When a #define
expression includes __LINE__ for example.)
The value of an object with external linkage that is defined
in some other translation unit cannot be known at compile time in C, and
cannot (with defined behavior at least) be different in different
translation units, no matter what fancy tricks you use. The closest
equivalents in your language works quite differently, and that changes
the implications of "compile time".

Well actually I'm not so interested in the values of objects that use
storage, not at compile time anyway. That is an issue for C because it's
what C uses for 'const ints', part of the OP's problem.

(If 'proper' named constants were used (even enums), then the problem
wouldn't arise, and C doesn't allow enums to be external.)

However, if the value of such an object, in the module where it's defined,
is determinable by the compiler to be constant, then there's no reason why
that information can't be 'exported' in the same way that a plain number
could be.

Although I agree a lot of the existing features of C can make that much more
difficult than it need be. In that case the compiler would need to be able
to determine whether that value was also invariant (be the same on repeated
compilations), not defined recursively (perhaps defined in terms of itself
via a chain of extern statements!) and so on. So perhaps in this case it's
more trouble than it's worth.
 
B

BartC

c lacks an lengthof() operator, it could be
done easily and also use efficiently (more
efficient than size passing)

You mean like this:

#define lengthof(x) (sizeof(x)/sizeof(x[0]))

In C it's all done with macros.

Oh I forgot, you don't like macros...
 
F

fir

W dniu poniedziałek, 19 listopada 2012 12:35:39 UTC+1 użytkownik Bart napisał:
c lacks an lengthof() operator, it could be
done easily and also use efficiently (more
efficient than size passing)

You mean like this:

#define lengthof(x) (sizeof(x)/sizeof(x[0]))

In C it's all done with macros.

Oh I forgot, you don't like macros...

yes, i do not use macros

internal lengthof() would be better for
many reasons, also this macro would not
work in all situations, Mechanism i described
beore would work

though to rethink is one question, this
hidden length variables naming and related
wuestions, they should be seenable thru the
linker from different modules, but possibly
(not sure to that) not stright accesible
to programmer (in favor of lengthof operator)
- maybe i am not sure to that (need to rethink it yet more)

(professor fir (aka grunge fightr))
 
J

James Kuyper

c lacks an lengthof() operator, it could be
done easily and also use efficiently (more
efficient than size passing)

You mean like this:

#define lengthof(x) (sizeof(x)/sizeof(x[0]))

In C it's all done with macros.

Oh I forgot, you don't like macros...

I'm reasonably sure he's interested in an operator that could be applied
to a pointer (not an array) to give the length of the array it points
at. This is quite feasible, but would require pointers to carry more
information than is currently required. You'd also have to add a feature
to the language to create a pointer to only part of an array; lengthof()
would then give the length of the desired part of the array, rather than
the entire array.

The key problem is that mandating support for such a feature would
require that ALL pointers carry this information. The collection and
transmission of that extra information could be optimized away in some
circumstances, but not in the general case. With pointers being such a
fundamental feature of C, that would significantly degrade the
performance of all programs, even the ones that don't make any use of
lengthof(). One of the key design principles for the C language is that
you shouldn't have to pay for the costs of features that your code
doesn't use.
 
F

fir

W dniu poniedziałek, 19 listopada 2012 14:21:40 UTC+1 użytkownik James Kuyper napisał:
c lacks an lengthof() operator, it could be
done easily and also use efficiently (more
efficient than size passing)

You mean like this:

#define lengthof(x) (sizeof(x)/sizeof(x[0]))

In C it's all done with macros.

Oh I forgot, you don't like macros...


I'm reasonably sure he's interested in an operator that could be applied

damn, youre right here, I mislooked one thing
here (must rethink that and modify, the other
parts of my reasoning was good)
to a pointer (not an array) to give the length of the array it points
at. This is quite feasible, but would require pointers to carry more
information than is currently required. You'd also have to add a feature
to the language to create a pointer to only part of an array; lengthof()
would then give the length of the desired part of the array, rather than
the entire array.



The key problem is that mandating support for such a feature would
require that ALL pointers carry this information. The collection and
transmission of that extra information could be optimized away in some
circumstances, but not in the general case. With pointers being such a
fundamental feature of C, that would significantly degrade the
performance of all programs, even the ones that don't make any use of
lengthof(). One of the key design principles for the C language is that
you shouldn't have to pay for the costs of features that your code
doesn't use.

sure, I do agree with that :/
 
J

James Kuyper

On 11/19/2012 06:35 AM, BartC wrote: ....
#define lengthof(x) (sizeof(x)/sizeof(x[0]))

In C it's all done with macros.
....
I'm reasonably sure he's interested in an operator that could be applied
to a pointer (not an array) to give the length of the array it points
at.

Correction: if pointer did point at an array:

int (*parray)[15];

lengthof(*parray) would gives 15, the desired value. That's not the
problematic case. It's pointers that point at the first element of an
array (such as "Hello world!") that lengthof() doesn't handle in the
desired fashion.
 
F

fir

sure, I do agree with that :/

(thoug i disagree if you say that every
pointer used then would have to contain
additional lengthof information, It would
be necessary only for arrays (pointers to
many)
It can be distinguished by definietion

foo(Type1 p1[], Type2* p2)
{
// here pi could be fat pointer
// p2 normal thin pointer
}

this distinguish could be good for c
language (even without usage of fat pointers
just static control - some control over
over dereferencing pointers-to-one could
be much usefull) - but this is side thing

as to array pointers there fat pointers had appeared again :/ I do not like tem to much
- must rethink it over again
 
B

BartC

James Kuyper said:
c lacks an lengthof() operator, it could be
#define lengthof(x) (sizeof(x)/sizeof(x[0]))
I'm reasonably sure he's interested in an operator that could be applied
to a pointer (not an array) to give the length of the array it points
at. This is quite feasible, but would require pointers to carry more
information than is currently required. You'd also have to add a feature
to the language to create a pointer to only part of an array; lengthof()
would then give the length of the desired part of the array, rather than
the entire array.

The key problem is that mandating support for such a feature would
require that ALL pointers carry this information.

I think we discussed this before. My suggestion would be to have two kinds
of pointers: what we have now, and 'fat' pointers consisting of a pointer,
and a length (what I called 'slices').

This fat pointer need do nothing more than formalise what is done now, when
a pointer+length is passed, or a struct containing a pointer and length is
created, and that is passed.

But being part of the language, the (pointer,length) type can be used with
any target type, while you'd need to define a new struct for each target, or
use lots of untidy casts.

(I partly lost interest in implementing such a type for my own projects, for
this level of language. You reserve those goodies for the next level where
you can do it properly! For example, the logical next step is to have a
flexible array type (where the size can vary, usually upwards). But for that
purpose, a (pointer,length) type isn't enough.)
With pointers being such a
fundamental feature of C, that would significantly degrade the
performance of all programs, even the ones that don't make any use of
lengthof().

No, you'd leave ordinary pointers alone. They're used in such a variety of
ways anyway, that a length attribute would often be meaningless. (For
example when they point to an individual value; it may or may not be part of
a homogeneous set, but you don't care if it is.)
 
B

BartC

James Kuyper said:
On 11/19/2012 06:35 AM, BartC wrote: ...
#define lengthof(x) (sizeof(x)/sizeof(x[0]))

In C it's all done with macros.
...
I'm reasonably sure he's interested in an operator that could be applied
to a pointer (not an array) to give the length of the array it points
at.

Correction: if pointer did point at an array:

int (*parray)[15];

lengthof(*parray) would gives 15, the desired value. That's not the
problematic case. It's pointers that point at the first element of an
array (such as "Hello world!") that lengthof() doesn't handle in the
desired fashion.

That's another problem, distinguishing between a char array itself, and the
zero-terminated string it might contain. Perhaps it's better to assume a
char array, and use strlen() for strings, where you know there will be extra
overhead.

(However. once a string length *has* been calculated, you can then construct
a (pointer,length) type, and now you have counted strings! As well as string
slices, pointing to a substring in the middle of a string, etc.)
 
J

James Kuyper

(thoug i disagree if you say that every
pointer used then would have to contain
additional lengthof information, It would
be necessary only for arrays (pointers to
many)

The C standard treats pointers to single objects as if they were
pointers to the first element of a 1-element array. This concept is
built into C pointer arithmetic.
It can be distinguished by definietion

foo(Type1 p1[], Type2* p2)

While I routinely make that distinction in my own code, it's just a
coding convention; as far as C itself is concerned, there's no
distinction between p1 and p2, and a lot of existing code relies upon
the fact that this is the case - one form is used in the function
declaration, a different form is used in the function definition, but
since C says that they are equivalent, that's perfectly acceptable.
Existing code will break if the two declarations indicate different
argument passing mechanisms.
One of the C committee's guiding principles is to avoid changes that
would break existing code.
 
E

Eric Sosman

Eric Sosman said:
Because, at compile time for file2.c, file1.c is not visible, and the
Well, OK, in the language I had in mind
... it would look like this:
[...]

You've missed James' point. Try this example:

/* file1.c */
const int table_max = 100;

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

/* victim.c */
extern const int table_max;
int table[table_max];

From these three files I want to make two programs: One
that links file1.o+victim.o, the other using file2.o+victim.o.
Explain how table_max is a compile-time constant in victim.

We're talking about compile-time constants, not link-time ones.

Also about something that C might be made to do, not as it is now.
However I'm assuming that this new C would need still the dimension of
table[] - table_max - to be known to the compiler.

So when victim is compiled, it will use the current value of table_max
in whichever file1 or file2 has been chosen. To create two programs with
two different values of table_max, requires recompilation of victim in
each case.

... 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.
Yes, there are still build dependencies, the same as there might be now
when you use header files:

you compiled victim.c a month ago, using a header file1.h containing
some particular function prototype which is contained in file1.c. Today
you modify the function in file1.c so that the prototype needs to
change. victim.c needs to be recompiled if you want to link it with a
file1 object file created today.

An #include'd file or header is part of the "translation unit,"
and it makes sense to require re-translation when any part of the
translation unit changes. 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.
 
E

Eric Sosman

James Kuyper said:
On 11/19/2012 06:35 AM, BartC wrote: ...
#define lengthof(x) (sizeof(x)/sizeof(x[0]))

In C it's all done with macros. ...
I'm reasonably sure he's interested in an operator that could be applied
to a pointer (not an array) to give the length of the array it points
at.

Correction: if pointer did point at an array:

int (*parray)[15];

lengthof(*parray) would gives 15, the desired value. That's not the
problematic case. It's pointers that point at the first element of an
array (such as "Hello world!") that lengthof() doesn't handle in the
desired fashion.

That's another problem, distinguishing between a char array itself, and
the zero-terminated string it might contain. Perhaps it's better to
assume a char array, and use strlen() for strings, where you know there
will be extra overhead.

(However. once a string length *has* been calculated, you can then
construct a (pointer,length) type, and now you have counted strings! As
well as string slices, pointing to a substring in the middle of a
string, etc.)

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.

(Digression:)

Everybody's always coming up with ideas about things that could
be added to C, and making a case for their usefulness. In C99 we
saw the fruit of invention: Lots of new and useful features were
added, and what happened? Adoption was dismally slow, and now in
C11 we've got __STDC_NO_VLA__ and __STDC_NO_COMPLEX__ and six more
"conditional feature" macros: one hundred ninety-two[*] distinct
languages, all legitimately called "C." This is exactly the kind
of fragmentation ANSI C set out to minimize, and I think we can
trace its explosive resurgence to feature creep. Let's at least
make it no worse, okay?

[*] Not 256, because two of the macros are interdependent.
 
F

fir

just static control - some control over
over dereferencing pointers-to-one could
be much usefull) - but this is side thing

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 :/
 

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
473,769
Messages
2,569,582
Members
45,057
Latest member
KetoBeezACVGummies

Latest Threads

Top