On Sunday, August 12, 2018 at 6:57:02 AM UTC-4, Bart wrote:
> On 12/08/2018 04:15,
james...@alumni.caltech.edu wrote:
> > On Saturday, August 11, 2018 at 6:11:53 PM UTC-4, Bart wrote:
>
> >> I mean whatever James means by "C", as he clearly thinks the language I
> >> am using and generating is not C.
> >
> > No, I said you weren't compiling it as C code. And that comment was only
> > in reference to your compilations that failed to set the options needed
> > to put gcc into a standard-conforming mode. You did show one compilation
> > using -std=c11, and that compilation was in fact compilation as C code.
>
> No. I showed four successive compilations using -std, followed by the
> comment 'You still think I'm not compiling C?'.
>
> You said 'No, it's GnuC'.
Yes, and when I said, "No, it's GnuC", I was referring to the two
compilations that did not use -std. That was not, in any sense, a
comment about the four compilations that used -std. Looking back, I see
that I should have placed the comment earlier, to make that distinction
clear. I apologize for placing it incorrectly.
> > What I want you to do (I know it's far too much to ask, but you did ask
> > what I want) is for you to stop complaining about the fact that when you
> > insist on compiling your code as GnuC code, the compiler behaves in
> > accordance with the rules of GnuC, which are often significantly
> > different from the rules of C.
>
> If I take this program (c.c):
>
> a,b,c; # implicit int
>
> fred(); # implicit int and () params
>
> main()
> {
> puts("hi there"); # implicit func decl
> fred(10);
> fred("twenty","thirty"); # contradictory args to fred
> }
>
> and compile as:
>
> gcc -c c.c
>
> then I do get a bunch of warnings, not errors. But if I follow your
> advice and compile it like this:
>
> gcc -c -std=c11 -pedantic c.c
>
> Then I get exactly the same warnings. It MAKES NO DIFFERENCE!
I'll take your word for it. GnuC is a very different language than C,
but it is also very similar to C, and this is an example of how it's
similar. I pay attention to both warnings and errors - and I treat a
warning message that is valid the same as a valid error message, so the
fact that it generates warning messages rather than error messages
doesn't matter to me.
> > It's not about writing code in the C language. It's about compiling it
> > as C code. When you use gcc without -std=c90, or c99, or c11, you're
> > not compiling it as C code, regardless of what you were thinking when
> > you wrote it.
>
> And my little test shows it makes no difference. Do you really think
> gnuC is so much more lax about things that matter? Seems silly to add so
No, the key point is not that it's lax, but that it's different.
> many features make the language better, but then say, 'Let's be more
> forgiving than standard C about implicit ints'!
Why? The version you're using implements GnuC90 by default, which shares
with C90 the fact that implicit int was considered perfectly normal. Why
shouldn't it be forgiving of implicit int?
> > Actually, it doesn't - you're unreasonable about what you want to do.
> > Properly written C code does NOT trigger thousands of warnings when
> > using -pedantic.
>
> On my intended platforms, void*, T* and T(*)() pointers can be cast to
> each other and they all share the same 32- or 64-bit representation. So
> here the compiler is being unreasonable. Avoiding casts to/from function
> pointers sees especially fiddly.
>
> How would YOU rewrite a table like this of mixed function pointers:
>
> void *table[] = {malloc, realloc, free, printf, puts};
I'd use void (*)(void), rather than void*, as Ben showed you.
> How would you use such a pointer afterwards for calling it?
> Say, calling the pointer at table[2] knowing that it takes a void* argument.
(*(void (*)(void*))table[2])(ptr);
That isn't quite correct, however. The truth is, I would never write code
like that. Using a function pointer to call a function when the function
pointer points at is incompatible with the definition of the function is
undefined behavior of the worst kind, so I would not use a generic
function pointer unless I combined it with strong measures to make sure
I kept proper track of the actual type of the function it points at. In
older C code, I would put the function pointer inside a struct, with
another member of the struct devoted to keeping track of the type of the
function pointed at. I would do my best to make sure that the type
identifier was kept synchronized with the pointer. In modern C, I'd use
a _Generic expression in the process of setting the type code. In C++,
I'd use templates for the same purpose.
Now, a lot of the C code you work with is computer generated. If your
code generator makes sure that the second element of the array always
points at a function with the same interface as free(), and if your code
generator makes sure that the second pointer is never used to call a
function in any way other than using that same interface, then it's safe
- because of your code generator, not because the generated code is
itself safe. Since I don't write code generators, but actual source
code, it's vitally important to me that the compiler be able to catch
type errors like that, which would be impossible with your code.
A scheme similar to the one you describe was used by C++ compilers that
generated C code as an intermediate step, for purposes of implementing
virtual function tables. But it is properly done using an array of
function pointers, not object pointers.