Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Who is right?

324 views
Skip to first unread message

jacobnavia

unread,
Aug 26, 2018, 4:17:27 AM8/26/18
to
Consider this code:

enum attrib { a1,a2};
struct s { char *name; enum attrib Attrib[6];};

struct s S = {"foo",{} };

gcc -c -Wall foo.c

No warnings or errors

lcc -c foo.c
Error foo.c: 4 illegal expression

Is it legal to use "{}" instead of "{0}" ?

Ian Collins

unread,
Aug 26, 2018, 4:26:11 AM8/26/18
to
Make gcc compile it as C!

gcc -std=c99 -pedantic x.c
x.c: In function ‘main’:
x.c:6:23: warning: ISO C forbids empty initializer braces [-Wpedantic]
struct s S = {"foo",{} };

--
Ian.

jacobnavia

unread,
Aug 26, 2018, 5:02:55 AM8/26/18
to
Thanks Ian. Note that if you do not add the -pedantic the warning
doesn't appear.

So, gcc is wrong this time. No bugs in my side, that's good news...

jacob

Bart

unread,
Aug 26, 2018, 6:16:03 AM8/26/18
to
You don't need to specify a C standard. Just -pedantic will do.

It's funny how every other compiler (except tcc) treats that as a fatal
syntax error. But gcc has to be prodded into even treating it as a
warning. (tcc generally tries to emulate gcc.)

Which means that a program developed using gcc and without using
-pedantic (or they use that and ignore such warnings), is likely to be
less portable to anything else.

--
bart

Noob

unread,
Aug 26, 2018, 7:03:00 AM8/26/18
to

James Kuyper

unread,
Aug 26, 2018, 8:00:32 AM8/26/18
to
Correct:


"initializer:
assignment-expression
{ initializer-list }
{ initializer-list , }

initializer-list:
designation opt initializer
initializer-list , designation opt initializer"
(6.7.9p1)

Note that initializer_list isn't marked as optional, and an initializer
list can't be empty.

David Brown

unread,
Aug 26, 2018, 10:48:59 AM8/26/18
to
gcc by default is laxer than the standards. The gcc developers have
presumably reasoned that it can be convenient to have an empty
initialiser sometimes, so they allow it in their extended version of the
language. If you specifically ask the compiler to be stricter, it is.

So gcc is not "wrong" here, it is just slightly extending the syntax of
C in an obvious way. gcc does not claim to follow the standards closely
unless you use the -pedantic flag (and even that has limits). If you
give gcc a flag like "-std=c99", it will - baring bugs,
misunderstandings or missing features - promise to accept any C99
compatible code. But it does not promise to reject code that isn't C99
compatible.

Of course, your compiler is certainly not wrong here either - the
standards say {} is a syntax error (see section 6.7.9 syntax) and you
are under no obligation to support an extension just because gcc does.


Ben Bacarisse

unread,
Aug 26, 2018, 10:49:29 AM8/26/18
to
jacobnavia <ja...@jacob.remcomp.fr> writes:
<snip>
> Thanks Ian. Note that if you do not add the -pedantic the warning doesn't appear.
>
> So, gcc is wrong this time.

It's a bit harsh to say it's wrong. It's just accepting an extension by
default. I thought lcc does that too (though not with this specific
extension of course).

It's vary common for a compiler to accept some language not entirely
unlike C by default. I'd rather the default be strict conformance, but
that ship sailed a long time ago.

--
Ben.

David Brown

unread,
Aug 26, 2018, 10:54:44 AM8/26/18
to
That is why people who write code that should be portable generally
recommend using the "-pedantic" flag with gcc.

gcc implements extended versions of the C language standards. They do
this because the gcc developers and many gcc users think the extended
versions are improvements over the standard versions. If you don't want
the extended versions, you can use flags to pick exactly which C version
you want. Some people feel gcc should use one of the standard versions
by default. Some people feel you should always specify exactly which
version you want. (There is a fair amount of overlap in these groups.
Personally, I think gcc should refuse to compile at all unless you
explicitly give it a "-std" option - but I realise that would break
existing usage.)

Bart

unread,
Aug 26, 2018, 12:13:43 PM8/26/18
to
On 26/08/2018 15:54, David Brown wrote:
> On 26/08/18 12:15, Bart wrote:

>> Which means that a program developed using gcc and without using
>> -pedantic (or they use that and ignore such warnings), is likely to be
>> less portable to anything else.
>>
>
> That is why people who write code that should be portable generally
> recommend using the "-pedantic" flag with gcc.

Apart from the people who don't. Then you end up with software that will
only compile with gcc.

(Hint: if you want portable code that works with a range of compilers,
then test it with a range of compilers. The more custom options it needs
to get it to work with each one, the less successful the effort has been.)

Using -pedantic is an extreme measure where a program has to be perfect
to pass without warnings, so that you have to fix things that are
harmless, and that are generally accepted elsewhere.

> gcc implements extended versions of the C language standards.

Specifying one of -std=c90, c99 or c11 frequently makes no difference.

Especially not to what are perceived by gcc as errors.

And it makes no difference in this example. So here it's a red herring.


--
bart

james...@alumni.caltech.edu

unread,
Aug 26, 2018, 1:08:37 PM8/26/18
to
On Sunday, August 26, 2018 at 6:16:03 AM UTC-4, Bart wrote:
> On 26/08/2018 09:26, Ian Collins wrote:
...
> > Make gcc compile it as C!
> >
> > gcc -std=c99 -pedantic x.c
> > x.c: In function ‘main’:
> > x.c:6:23: warning: ISO C forbids empty initializer braces [-Wpedantic]
> >    struct s S = {"foo",{} };
> >
>
> You don't need to specify a C standard. Just -pedantic will do.
>
> It's funny how every other compiler (except tcc) treats that as a fatal
> syntax error. But gcc has to be prodded into even treating it as a
> warning. (tcc generally tries to emulate gcc.)

Why do you consider that funny? It's not an error of any kind as far as GnuC is concerned. Why should it produce an error message that's required for a different language (C), but isn't an error in the one you requested it to compile?

> Which means that a program developed using gcc and without using
> -pedantic (or they use that and ignore such warnings), is likely to be
> less portable to anything else.

True, but many people (not me) consider GnuC code that can be compiled
anywhere that gcc is available to be portable enough.

Intelligent sane people who are concerned about the portability of their
code to compilers other than gcc don't use gcc without, at a minimum,
giving it the command line options needed to specify the particular
version of the particular language that they want it to compile, and
usually also -pedantic, if that language is any version of standard C.

james...@alumni.caltech.edu

unread,
Aug 26, 2018, 1:18:43 PM8/26/18
to
On Sunday, August 26, 2018 at 12:13:43 PM UTC-4, Bart wrote:
> On 26/08/2018 15:54, David Brown wrote:
> > On 26/08/18 12:15, Bart wrote:
>
> >> Which means that a program developed using gcc and without using
> >> -pedantic (or they use that and ignore such warnings), is likely to be
> >> less portable to anything else.
> >>
> >
> > That is why people who write code that should be portable generally
> > recommend using the "-pedantic" flag with gcc.
>
> Apart from the people who don't. Then you end up with software that will
> only compile with gcc.
>
> (Hint: if you want portable code that works with a range of compilers,
> then test it with a range of compilers. The more custom options it needs
> to get it to work with each one, the less successful the effort has been.)
>
> Using -pedantic is an extreme measure where a program has to be perfect
> to pass without warnings, so that you have to fix things that are
> harmless, and that are generally accepted elsewhere.

Code that is far less than perfect can easily pass -pedantic. Code has
to be as poorly written as yours for gcc -pedantic to have serious
problems with it.

> > gcc implements extended versions of the C language standards.
>
> Specifying one of -std=c90, c99 or c11 frequently makes no difference.

Well, they are very similar versions of C - it's pretty ordinary for
code to behave the same in all three.

> Especially not to what are perceived by gcc as errors.

Perhaps - it doesn't pay to attach too much importance to the
distinction they make between errors and warnings. However, if you look
only at diagnostics without worrying about that distinction, the version
of the C standard does matter, when it should (when the differences
between the versions matter to the code in question), particularly if
you're wise enough to add pedantic.

> And it makes no difference in this example. So here it's a red herring.

Because you didn't choose -pedantic.

Bart

unread,
Aug 26, 2018, 1:42:09 PM8/26/18
to
On 26/08/2018 18:08, james...@alumni.caltech.edu wrote:
> On Sunday, August 26, 2018 at 6:16:03 AM UTC-4, Bart wrote:
>> On 26/08/2018 09:26, Ian Collins wrote:
> ...
>>> Make gcc compile it as C!
>>>
>>> gcc -std=c99 -pedantic x.c
>>> x.c: In function ‘main’:
>>> x.c:6:23: warning: ISO C forbids empty initializer braces [-Wpedantic]
>>>    struct s S = {"foo",{} };
>>>
>>
>> You don't need to specify a C standard. Just -pedantic will do.
>>
>> It's funny how every other compiler (except tcc) treats that as a fatal
>> syntax error. But gcc has to be prodded into even treating it as a
>> warning. (tcc generally tries to emulate gcc.)
>
> Why do you consider that funny? It's not an error of any kind as far as GnuC is concerned. Why should it produce an error message that's required for a different language (C), but isn't an error in the one you requested it to compile?

You get the same result using any of these:

gcc -std=c90 -c c.c
gcc -std=c99 -c c.c
gcc -std=c11 -c c.c

So please explain why you are always going on about gcc compiling only gnuc.

It just seems to a thing with gcc that you have to do a lot of
persuasion to get it to even notice errors let alone take them seriously.

--
bart

Bart

unread,
Aug 26, 2018, 2:01:54 PM8/26/18
to
On 26/08/2018 18:18, james...@alumni.caltech.edu wrote:
> On Sunday, August 26, 2018 at 12:13:43 PM UTC-4, Bart wrote:

>> Using -pedantic is an extreme measure where a program has to be perfect
>> to pass without warnings, so that you have to fix things that are
>> harmless, and that are generally accepted elsewhere.
>
> Code that is far less than perfect can easily pass -pedantic. Code has
> to be as poorly written as yours for gcc -pedantic to have serious
> problems with it.

So why would anyone have any objection to (1) having -pedantic be turned
on by default; (2) having any transgressions always be fatal errors by
default?

>>> gcc implements extended versions of the C language standards.
>>
>> Specifying one of -std=c90, c99 or c11 frequently makes no difference.
>
> Well, they are very similar versions of C - it's pretty ordinary for
> code to behave the same in all three.
>
>> Especially not to what are perceived by gcc as errors.
>
> Perhaps - it doesn't pay to attach too much importance to the
> distinction they make between errors and warnings. However, if you look
> only at diagnostics without worrying about that distinction, the version
> of the C standard does matter, when it should (when the differences
> between the versions matter to the code in question), particularly if
> you're wise enough to add pedantic.
>
>> And it makes no difference in this example. So here it's a red herring.
>
> Because you didn't choose -pedantic.

So, let me get this right, gcc is a compiler which normally lets pretty
much everything through unquestioned. Unless you tell it to /stop/
pretty much everything getting through.

So it's either all or nothing.

--
bart

Richard Damon

unread,
Aug 26, 2018, 2:41:03 PM8/26/18
to
On 8/26/18 2:01 PM, Bart wrote:
>
> So why would anyone have any objection to (1) having -pedantic be turned
> on by default; (2) having any transgressions always be fatal errors by
> default?

People who prefer to be writing in GnuC instead of StdC, and maybe the
authors of gcc think these are the people who will be using gcc just out
of the box.

If you are going to be restricting yourself to 'Standard C', one
important thing is WHICH Standard, so you are going to be adding an
option to specify that also, so adding pedantic too isn't that hard.

As to why have some required diagnostics be 'just warnings', I suspect
these are things that the authors of gcc think they have a useful
extension defined for C that uses that syntax, so that may the default
just to warn. There is also an option (-pedantic-errors) which makes all
those required diagnostics into errors.

Keith Thompson

unread,
Aug 26, 2018, 3:31:46 PM8/26/18
to
Bart <b...@freeuk.com> writes:
[...]
> So why would anyone have any objection to (1) having -pedantic be turned
> on by default; (2) having any transgressions always be fatal errors by
> default?

I would not object to that. In fact I would prefer it.

[...]

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson

unread,
Aug 26, 2018, 3:37:11 PM8/26/18
to
Bart <b...@freeuk.com> writes:
[...]
> You get the same result using any of these:
>
> gcc -std=c90 -c c.c
> gcc -std=c99 -c c.c
> gcc -std=c11 -c c.c
>
> So please explain why you are always going on about gcc compiling only gnuc.

The -std=c.. options do not enable all required diagnostics.
"-gcc -std=c11" should correctly process correct C11 code (ignoring
bugs and unimplemented features), but it does not issue all
standard-required diagnostics, and so it is not a conforming C11
compiler. You need to add -pedantic or -pedantic-errors for that.

Please stop pretending not to know this. You are (I presume
deliberately) confusing others.

David Brown

unread,
Aug 26, 2018, 4:27:40 PM8/26/18
to
On 26/08/18 18:13, Bart wrote:
> On 26/08/2018 15:54, David Brown wrote:
>> On 26/08/18 12:15, Bart wrote:
>
>>> Which means that a program developed using gcc and without using
>>> -pedantic (or they use that and ignore such warnings), is likely to
>>> be less portable to anything else.
>>>
>>
>> That is why people who write code that should be portable generally
>> recommend using the "-pedantic" flag with gcc.
>
> Apart from the people who don't. Then you end up with software that will
> only compile with gcc.
>

Read what I wrote.

"People who write code that should be portable..."

People who write code that only needs to be compiled with gcc, don't
need "-pedantic". In fact, they should /not/ use "-pedantic" - if their
code is better (clearer, safer, easier to check for correctness, more
efficient) because it uses gcc extensions, then it should use gcc
extensions.

People who write code that needs to be portable on a range of compilers
should probably use "-pedantic". And since they will (presumably) be
checking with different compilers, they should notice the kind of
non-portable constructs that "-pedantic" would pick up.

> (Hint: if you want portable code that works with a range of compilers,
> then test it with a range of compilers. The more custom options it needs
> to get it to work with each one, the less successful the effort has been.)
>

I agree that for portable code you need to check with a range of
compilers. I totally disagree that avoiding options is necessary. You
need to use whatever options the compiler needs to give the effect you
want. So if your code is portable C99, you need whatever options the
compilers require in order to accept C99 code. Trying to avoid that
sort of thing is obsessive behaviour that results in worse code as you
try to make it work with an intersection of the C variations and
versions supported by a range of tools. It is far better to pick a C
standard, include any particular extras or implementation-defined
behaviour that are necessary, appropriate to the targets, or at least
commonly implemented and of significant benefit to the code, and then
ensure that all compilers you use are configured to suit that standard
or a subset of it. (i.e., if you need C99 then it's fine with gnu99 or
C11 - but not gnu90 or C89.)

And of course you use far more options while developing and checking the
code.


> Using -pedantic is an extreme measure where a program has to be perfect
> to pass without warnings, so that you have to fix things that are
> harmless, and that are generally accepted elsewhere.

No, it is not extreme - it is a flag that tells gcc to emit the
diagnostics required by the standards, plus a few others that indicate
syntax or constraint errors even though the standards don't insist on a
diagnostic. Code that complies to a given C standard will not give
warnings from -pedantic. So if you are getting -pedantic warnings, your
code is not following the standards. Such warnings are /not/ harmless,
and if you want very portable code, you need to fix it.

If you decide your "portable" code should only be somewhat portable, and
allow some non-standard behaviour, then it gets more complicated.

>
>> gcc implements extended versions of the C language standards.
>
> Specifying one of -std=c90, c99 or c11 frequently makes no difference.

It makes no difference if your code follows the common subset (which is,
almost entirely, C90) of these. If your code uses C11 or C99 features,
it /will/ make a difference.

But you need to understand what these flags mean. If you say
"-std=c90", you are saying "accept any correctly written C90 program".
You are /not/ saying "reject any program that is not entirely C90
compliant". The "-pedantic" flag is an addition to this to say "be
fussier", but even then the compiler can't reject all nonconformities as
that is an impossible problem.

>
> Especially not to what are perceived by gcc as errors.
>
> And it makes no difference in this example. So here it's a red herring.
>

As has been pointed out, giving gcc a standard and asking for more
accurate compliance checking with -pedantic /does/ give a result. (It's
a warning, but you can make it an error if you want.)

Bart

unread,
Aug 26, 2018, 4:27:40 PM8/26/18
to
On 26/08/2018 20:37, Keith Thompson wrote:
> Bart <b...@freeuk.com> writes:
> [...]
>> You get the same result using any of these:
>>
>> gcc -std=c90 -c c.c
>> gcc -std=c99 -c c.c
>> gcc -std=c11 -c c.c
>>
>> So please explain why you are always going on about gcc compiling only gnuc.
>
> The -std=c.. options do not enable all required diagnostics.
> "-gcc -std=c11" should correctly process correct C11 code (ignoring
> bugs and unimplemented features), but it does not issue all
> standard-required diagnostics, and so it is not a conforming C11
> compiler. You need to add -pedantic or -pedantic-errors for that.
>
> Please stop pretending not to know this. You are (I presume
> deliberately) confusing others.

James is the one doing that, not me.

He is continually saying that all these woes are because someone is not
compiling C.

But presumably, with any of these three options, gcc is compiling actual
C, and not gnuC, yes?

Keith Thompson

unread,
Aug 26, 2018, 4:52:33 PM8/26/18
to
David Brown <david...@hesbynett.no> writes:
[...]
> But you need to understand what these flags mean. If you say
> "-std=c90", you are saying "accept any correctly written C90 program".
> You are /not/ saying "reject any program that is not entirely C90
> compliant". The "-pedantic" flag is an addition to this to say "be
> fussier", but even then the compiler can't reject all nonconformities as
> that is an impossible problem.
[...]

That depends on what you mean by "nonconformities" (a term that's not
defined by the C standard). A conforming C compiler can *and must*
be able to diagnose all violations of syntax rules and constraints.

Keith Thompson

unread,
Aug 26, 2018, 5:04:10 PM8/26/18
to
Bart <b...@freeuk.com> writes:
> On 26/08/2018 20:37, Keith Thompson wrote:
>> Bart <b...@freeuk.com> writes:
>> [...]
>>> You get the same result using any of these:
>>>
>>> gcc -std=c90 -c c.c
>>> gcc -std=c99 -c c.c
>>> gcc -std=c11 -c c.c
>>>
>>> So please explain why you are always going on about gcc compiling only gnuc.
>>
>> The -std=c.. options do not enable all required diagnostics.
>> "-gcc -std=c11" should correctly process correct C11 code (ignoring
>> bugs and unimplemented features), but it does not issue all
>> standard*-required diagnostics, and so it is not a conforming C11
>> compiler. You need to add -pedantic or -pedantic-errors for that.
>>
>> Please stop pretending not to know this. You are (I presume
>> deliberately) confusing others.
>
> James is the one doing that, not me.
>
> He is continually saying that all these woes are because someone is not
> compiling C.
>
> But presumably, with any of these three options, gcc is compiling actual
> C, and not gnuC, yes?

That depends on what you mean by "compiling actual C". "gcc -std=c11"
will accept, without warnings, many C programs that are not conforming
ISO C, for which the standard requires a diagnostic. For example, it
quietly accepts gcc-specific statement expressions. Adding "-pedantic"
or "-pedantic-errors" will cause it to issue a diagnostic.

I could discuss the fine details of what James meant by "not compiling
C" and whether he could have used a more accurate phrase, but that would
be boring.

Chris M. Thomasson

unread,
Aug 26, 2018, 6:20:20 PM8/26/18
to
Fwiw, I always combine -pedantic with -Wall and -Wextra. Perhaps even a
-Wfatal-errors... ;^)

james...@alumni.caltech.edu

unread,
Aug 26, 2018, 7:42:34 PM8/26/18
to
On Sunday, August 26, 2018 at 2:01:54 PM UTC-4, Bart wrote:
> On 26/08/2018 18:18, james...@alumni.caltech.edu wrote:
> > On Sunday, August 26, 2018 at 12:13:43 PM UTC-4, Bart wrote:
>
> >> Using -pedantic is an extreme measure where a program has to be perfect
> >> to pass without warnings, so that you have to fix things that are
> >> harmless, and that are generally accepted elsewhere.
> >
> > Code that is far less than perfect can easily pass -pedantic. Code has
> > to be as poorly written as yours for gcc -pedantic to have serious
> > problems with it.
>
> So why would anyone have any objection to (1) having -pedantic be turned
> on by default; (2) having any transgressions always be fatal errors by
> default?

I don't know for sure - why don't you ask the question of someone who
might actually be able to answer it, in a gcc-oriented forum?
I've heard that the -pedantic option was named that way by people who
disapproved of the features it turned on, which would also explain why
it was an option rather than the default. I've also heard that the
people who are now responsible for gcc's design don't feel that way -
either because they changed their minds, or because they are different
people from the ones who named it "-pedantic. But I can't vouch for the
truth of either claim from my personal exerience, which is an example of
why it's a question better asked in a more appropriate forum. However,
I can explain to you why it's difficult to change such things at this
point - too many existing build systems would fail if it were changed.
Lots of people have reasons, both valid and invalid, for deliberately
writing code that would be rejected by -pedantic.

As for item 2, its -Werror and -pedantic-errors. I believe that they are
options, rather than the default, for much the same reason that
-pedantic is. But there's another factor, as well - I don't use either
of those options because doing so would prevent me from using my own
judgment about warnings triggered by things for which a diagnostic is
not mandatory. That reflects the fact that I have a very good
understanding of what is mandated, prohibited, allowed and deprecated by
the C standard, and why. That wouldn't be a reasonable approach for
someone with your level of understanding.

> >>> gcc implements extended versions of the C language standards.
> >>
> >> Specifying one of -std=c90, c99 or c11 frequently makes no difference.
> >
> > Well, they are very similar versions of C - it's pretty ordinary for
> > code to behave the same in all three.
> >
> >> Especially not to what are perceived by gcc as errors.
> >
> > Perhaps - it doesn't pay to attach too much importance to the
> > distinction they make between errors and warnings. However, if you look
> > only at diagnostics without worrying about that distinction, the version
> > of the C standard does matter, when it should (when the differences
> > between the versions matter to the code in question), particularly if
> > you're wise enough to add pedantic.
> >
> >> And it makes no difference in this example. So here it's a red herring.
> >
> > Because you didn't choose -pedantic.
>
> So, let me get this right, gcc is a compiler which normally lets pretty
> much everything through unquestioned. Unless you tell it to /stop/
> pretty much everything getting through.
>
> So it's either all or nothing.

No, it's got lots of configuration options between "all" and "nothing".
-pedantic doesn't even come close to "nothing". You have to add at least
-Wall to get a decent collection of warnings, and certain kinds of
errors aren't even noticed unless you have a sufficiently high
optimization level. That's because the higher optimization levels
require it to do a more careful analysis of the code, and as a result of
that analysis it becomes capable of detecting some errors that are too
subtle for it to notice normally. Some people swear by -Wextra, but
that's going a little too far for my tastes - which might give you a
hint as to why there's so many options. Of course, it's a hint you're
inherently incapable to receiving,.

It's only because your code routinely and seriously violates the C
standard that -pedantic seems like it rejects almost everything.

James Kuyper

unread,
Aug 26, 2018, 7:48:58 PM8/26/18
to
On 08/26/2018 04:27 PM, David Brown wrote:
...
> No, it is not extreme - it is a flag that tells gcc to emit the
> diagnostics required by the standards, plus a few others that indicate
> syntax or constraint errors even though the standards don't insist on a
> diagnostic.

There's no such thing as code with syntax errors or constraint violation
for which the C standard does not "insist on a diagnostic": "A
conforming implementation shall produce at least one diagnostic message
(identified in an implementation-defined manner) if a preprocessing
translation unit or translation unit contains a violation of any syntax
rule or constraint, even if the behavior is also explicitly specified as
undefined or implementation-defined." (5.1.1.3p1).

james...@alumni.caltech.edu

unread,
Aug 26, 2018, 7:59:44 PM8/26/18
to
How can it be compiling it as C code if the compiler fails to produce
diagnostics that the C standard specifies as mandatory? It is, after
all, precisely the absence of those diagnostics that you're complaining
about, isn't it? So how can you simultaneously treat the absence of
those diagnostics as unimportant?
You have to decide - are those diagnostics important? If so, the absence of -pedantic means they aren't compiling it as C code. If they aren't important, then simply using -std=c11 is brings it close enough to compiling the code as C, and you should not complain about the missing diagnostics.

Richard Damon

unread,
Aug 26, 2018, 8:41:38 PM8/26/18
to
You can have semantic violations outside a constraint section, which
will result in undefined behavior, but do not require a diagnostic. (One
example recently mentioned was multiple definitions in different
translation units). That may be the sort of thing David was thinking of.

Bart

unread,
Aug 26, 2018, 8:50:54 PM8/26/18
to
If I compile one of my generated files with -pedantic, I get 14000 lines
of warnings. From what I can see, there are two kinds:

(1) Conversion between function pointers and void*

(2) Problems with pointer signedness, because I use 'unsigned char' for
all my char types and string constants, while gcc uses 'char' with
unspecified sign.

So as far as I am concerned,there are two warnings. (Since usually
fixing one of 2000 equal warnings, will also fix the other 1999).

But is (2) really that serious a violation? To fix it, I would have to
put casts in front of every string constant, and everywhere I interface
to external C functions that use char-based parameters. That might shut
it up, but it will also hide any genuine type errors that might slip
past my translator.

If I add -Wall and _Wextra, I get 3000 more lines of warnings. Along the
lines of 'label defined but not used' or 'unused variable'. Again, are
these really serious violations?

My original sources are all in development and there will be variables
declared but not used in this particular rendering of the source to C.

My translation process can also generate lots of unused labels. I can
add a special pass to eliminate those, but I have better things to do.

The exact same original sources translate to x64 native code with none
of the problems I get from doing it in C. Believe me it puts
considerably less pressure on my mental health. There at least I only
have to deal with logic, not the temperamental compilers of some crazy
language.


--
bart

Bart

unread,
Aug 26, 2018, 9:12:14 PM8/26/18
to
On 27/08/2018 00:59, james...@alumni.caltech.edu wrote:
> On Sunday, August 26, 2018 at 4:27:40 PM UTC-4, Bart wrote:

>> But presumably, with any of these three options, gcc is compiling actual
>> C, and not gnuC, yes?
>
> How can it be compiling it as C code if the compiler fails to produce
> diagnostics that the C standard specifies as mandatory? It is, after
> all, precisely the absence of those diagnostics that you're complaining
> about, isn't it? So how can you simultaneously treat the absence of
> those diagnostics as unimportant?

Take this file:

int fn(void) {return;}

If I use my compiler WITH NO OPTIONS AT ALL it says:

Return value needed on line 1

If I use 'gcc -std=c11 -pedantic -Wall -Wextra' then all I get is a
warning. I have to add even more stuff to make it an error (and this can
be a serious one as garbage would be returned or it could even crash).

If I give it:

f() {fred(10);}

again no errors from gcc, only warnings. However I get an error here:

f() {malloc(10,20,30);}

not because malloc is undefined, but because there are too many
parameters. Now, how does it know about malloc, since I haven't declared
it? Is it allowed to have knowledge of stdlib.h when you haven't
included stdlib.h?

But back to the errors:

f() {fred(); fred(10,20,30);}

Again, just warnings. FFS, there are at least four things wrong with
that program! And I'm not talking about initialised unsigned char string
from non-signed bytes either.

My attitude to these things seems to be completely at odds with anyone
else's. Some things are obviously wrong; you don't need to give a
compiler a raft of options for it to tell you that. Such a program MUST
fail even without any options.

--

bart

Richard Damon

unread,
Aug 26, 2018, 9:53:35 PM8/26/18
to
(1) You should know that function pointers and void* data pointers are
not compatible, on some machines they are vastly different sizes.

(2) char IS a different type than signed char and unsigned char. C
intends that real character strings be stored in the type char (not the
signed or unsigned version of it). Unsigned char is sometimes better for
'raw bytes', and the types being different is useful.

The one big issue with chars, if they may be signed, is that to call
functions like isupper or toupper, you need to cast them to unsigned
char first, as they really want the int returned by something like
getchar().

warnings are not errors (but might or might not be required
diagnostics). Most compilers will generate an error for something that
might be an error or might not be. Unused symbols, if you know you meant
them to be unused, shouldn't be a problem, it can be a big help if you
didn't mean for that symbol to be unused. I would generally advise that
machine generated code should generally be compiled with a fairly low
warning level (unless you are trying to improve the 'quality' of the
generated code.

If you are generating code that depends on machine tricks (even if you
think ALL machines you can think of targeting do it that way), then to
use C as an intermediary language, you need to put the implementation
into a mode that allows those tricks or generate code that doesn't need
those tricks but follows the rules of the C Abstract machine. The C
language allows for both if you use it right.

james...@alumni.caltech.edu

unread,
Aug 26, 2018, 10:08:54 PM8/26/18
to
That certain is a problem, but it's neither a syntax error nor a
constraint violation.

james...@alumni.caltech.edu

unread,
Aug 26, 2018, 10:09:34 PM8/26/18
to
On Sunday, August 26, 2018 at 8:50:54 PM UTC-4, Bart wrote:
> On 27/08/2018 00:42, james...@alumni.caltech.edu wrote:
> > On Sunday, August 26, 2018 at 2:01:54 PM UTC-4, Bart wrote:
>
> >> So it's either all or nothing.
> >
> > No, it's got lots of configuration options between "all" and "nothing".
> > -pedantic doesn't even come close to "nothing". You have to add at least
> > -Wall to get a decent collection of warnings, and certain kinds of
> > errors aren't even noticed unless you have a sufficiently high
> > optimization level. That's because the higher optimization levels
> > require it to do a more careful analysis of the code, and as a result of
> > that analysis it becomes capable of detecting some errors that are too
> > subtle for it to notice normally. Some people swear by -Wextra, but
> > that's going a little too far for my tastes - which might give you a
> > hint as to why there's so many options. Of course, it's a hint you're
> > inherently incapable to receiving,.
> >
> > It's only because your code routinely and seriously violates the C
> > standard that -pedantic seems like it rejects almost everything.
>
> If I compile one of my generated files with -pedantic, I get 14000 lines
> of warnings. From what I can see, there are two kinds:
>
> (1) Conversion between function pointers and void*

Unambiguously undefined behavior in C.

> (2) Problems with pointer signedness, because I use 'unsigned char' for
> all my char types and string constants, while gcc uses 'char' with
> unspecified sign.
>
> So as far as I am concerned,there are two warnings. (Since usually
> fixing one of 2000 equal warnings, will also fix the other 1999).
>
> But is (2) really that serious a violation? To fix it, I would have to
> put casts in front of every string constant, and everywhere I interface
> to external C functions that use char-based parameters. That might shut
> it up, but it will also hide any genuine type errors that might slip
> past my translator.
...
> The exact same original sources translate to x64 native code with none
> of the problems I get from doing it in C.

Then I strongly recommend going with x64 native code and abandoning a language you're tempermentally incapable of learning to use correctly.

David Brown

unread,
Aug 27, 2018, 2:03:23 AM8/27/18
to
On 26/08/18 22:52, Keith Thompson wrote:
> David Brown <david...@hesbynett.no> writes:
> [...]
>> But you need to understand what these flags mean. If you say
>> "-std=c90", you are saying "accept any correctly written C90 program".
>> You are /not/ saying "reject any program that is not entirely C90
>> compliant". The "-pedantic" flag is an addition to this to say "be
>> fussier", but even then the compiler can't reject all nonconformities as
>> that is an impossible problem.
> [...]
>
> That depends on what you mean by "nonconformities" (a term that's not
> defined by the C standard). A conforming C compiler can *and must*
> be able to diagnose all violations of syntax rules and constraints.
>

gcc is not a conforming (to any version of the standard) C compiler.
Using "-std=c90" does not make it conforming either - it just makes it a
bit closer (it turns off extensions that conflict with the standard, so
that you can use "typeof" and "asm" as identifiers rather than extended
keywords - but it does not disable non-conflicting extensions). Using
"-pedantic" or "-pedantic-errors" makes it closer still, but AFAIK it
still doesn't get all the way to being entirely conforming. (I don't
know of any other compiler that is /entirely/ conforming either.)

I don't think a "conforming C compiler" must diagnose /all/ violations
of syntax rules and constraints - just those that require a diagnostic.
Syntax rules usually can be fully checked, but there are lots of
constraints for which the compiler cannot check at compile-time.

David Brown

unread,
Aug 27, 2018, 2:07:34 AM8/27/18
to
After reading these posts, I can see that is exactly what I was thinking
of. Breaking these semantic violations is undefined behaviour which
does not require a diagnostic.

Sorry for the confusion, and thanks to you, James and Keith for the
corrections.

David Brown

unread,
Aug 27, 2018, 2:09:22 AM8/27/18
to
This last paragraph is confusing constraints and requirements given in
the "semantics" sections of the C standards - and is therefore wrong.
See also my reply to Richard's post.

Keith Thompson

unread,
Aug 27, 2018, 2:54:06 AM8/27/18
to
David Brown <david...@hesbynett.no> writes:
> On 26/08/18 22:52, Keith Thompson wrote:
>> David Brown <david...@hesbynett.no> writes:
>> [...]
>>> But you need to understand what these flags mean. If you say
>>> "-std=c90", you are saying "accept any correctly written C90 program".
>>> You are /not/ saying "reject any program that is not entirely C90
>>> compliant". The "-pedantic" flag is an addition to this to say "be
>>> fussier", but even then the compiler can't reject all nonconformities as
>>> that is an impossible problem.
>> [...]
>>
>> That depends on what you mean by "nonconformities" (a term that's not
>> defined by the C standard). A conforming C compiler can *and must*
>> be able to diagnose all violations of syntax rules and constraints.
>
> gcc is not a conforming (to any version of the standard) C compiler.
> Using "-std=c90" does not make it conforming either - it just makes it a
> bit closer (it turns off extensions that conflict with the standard, so
> that you can use "typeof" and "asm" as identifiers rather than extended
> keywords - but it does not disable non-conflicting extensions). Using
> "-pedantic" or "-pedantic-errors" makes it closer still, but AFAIK it
> still doesn't get all the way to being entirely conforming. (I don't
> know of any other compiler that is /entirely/ conforming either.)

Compilers are software, all software has bugs, therefore compilers have
bugs. Absolute 100% conformance may not be possible. The point is that
"gcc -std=cNN -pedantic" *attempts* to be conforming, and it comes
pretty close. (There may be a handful of C11 features that haven't been
implemented yet; I haven't checked lately.)

> I don't think a "conforming C compiler" must diagnose /all/ violations
> of syntax rules and constraints - just those that require a diagnostic.
> Syntax rules usually can be fully checked, but there are lots of
> constraints for which the compiler cannot check at compile-time.

You corrected this in a followup.

David Brown

unread,
Aug 27, 2018, 3:10:35 AM8/27/18
to
I can add my "what I've heard" to this. gcc (i.e., the developers
behind it) used to view themselves as pioneers pulling the C language
forward when no one else would. They added significant numbers of
extensions and enhancements, loosened restrictions they saw as too tight
(like this one), incorporated improvements from related languages (newer
C standards and C++ standards), and generally made what they felt was a
better language. In many ways they were right - they /did/ make the
language better. And they /were/ pioneering - several features in C99
and in C++ standards came from gcc extensions. But it also meant the
extensions were incompatible with other compilers, and were often
underspecified and their integration with the rest of the language was
poorly considered.

The current gcc leadership is much more conservative. They still add
new extensions to C, some of which could be viewed as radical (like
"__auto_type") - but these are generally taken from C++. Now they work
much more closely with the standards committees, and with other
compilers. Development of C as a language is mostly stagnated - it is a
stable language, for good and for bad. (C++ is the one that is changing
and moving forward.) The compiler, however, still improves - again,
with cooperation, specially with clang, to get a certain consistency in
command-line options, attribute syntaxes, and sanitizers.





David Brown

unread,
Aug 27, 2018, 3:27:37 AM8/27/18
to
On 26/08/18 20:01, Bart wrote:
> On 26/08/2018 18:18, james...@alumni.caltech.edu wrote:
>> On Sunday, August 26, 2018 at 12:13:43 PM UTC-4, Bart wrote:
>
>>> Using -pedantic is an extreme measure where a program has to be perfect
>>> to pass without warnings, so that you have to fix things that are
>>> harmless, and that are generally accepted elsewhere.
>>
>> Code that is far less than perfect can easily pass -pedantic. Code has
>> to be as poorly written as yours for gcc -pedantic to have serious
>> problems with it.
>
> So why would anyone have any objection to (1) having -pedantic be turned
> on by default; (2) having any transgressions always be fatal errors by
> default?

I would not object to -pedantic being the default - but I would disable
it myself, because I make use of gcc extensions. And I would not object
to transgressions being fatal errors - I already use -Werrors for most
of my builds.

But these will /never/ be the default options. A prime aim for such
vital programs as gcc is that there be consistency in them and you don't
break existing code or builds - just as this is a prime aim for the C
language. Almost any program that is valid C90 code - or even valid K&R
C code - will be valid C11 code with the same meaning. Almost any
program that builds correctly with "gcc <some options>" with gcc version
2.71 will also build correctly with gcc 9 and the same options. In
neither case is the backwards compatibility perfect, but a great deal of
effort is made to get as close as possible, and breaking changes are not
made without very significant motivation.

So the default is to do as the compiler always has done. And you use
compiler switches to choose to do better.

(gcc could, IMHO, be improved by collecting more of the useful switches
into groups targeted at developers working on new code. A
"-fno-obsolete" flag to disable all C11 obsolete behaviour would be nice.)

(gcc /does/ try to get newer changes in the defaults sometimes. They
work with some of the Linux distributors here. When there is a
suggestion to change a default, or add a new warning to -Wall or other
common flags, someone re-compiles the entire Debian base to see if the
change breaks anything.)

>
>>>> gcc implements extended versions of the C language standards.
>>>
>>> Specifying one of -std=c90, c99 or c11 frequently makes no difference.
>>
>> Well, they are very similar versions of C - it's pretty ordinary for
>> code to behave the same in all three.
>>
>>> Especially not to what are perceived by gcc as errors.
>>
>> Perhaps - it doesn't pay to attach too much importance to the
>> distinction they make between errors and warnings. However, if you look
>> only at diagnostics without worrying about that distinction, the version
>> of the C standard does matter, when it should (when the differences
>> between the versions matter to the code in question), particularly if
>> you're wise enough to add pedantic.
>>
>>> And it makes no difference in this example. So here it's a red herring.
>>
>> Because you didn't choose -pedantic.
>
> So, let me get this right, gcc is a compiler which normally lets pretty
> much everything through unquestioned. Unless you tell it to /stop/
> pretty much everything getting through.
>
> So it's either all or nothing.
>

You sound like some bad "Jewish mother" joke. You usually complain that
gcc has hundreds or thousands of flags, and now you are complaining that
it is one "all or nothing" flag. /Nothing/ will satisfy you but a
compiler that is fine-tuned to your exact personal preferences of the
week for compiling your code with a total disregard for everyone else
and all other C code.

Learn some C and write your code in C, and -pedantic will not throw up
any complaints. Look at the gcc reference pages and see what other
compiler flags would be useful for you.


David Brown

unread,
Aug 27, 2018, 4:01:03 AM8/27/18
to
On 27/08/18 02:50, Bart wrote:
> On 27/08/2018 00:42, james...@alumni.caltech.edu wrote:
>> On Sunday, August 26, 2018 at 2:01:54 PM UTC-4, Bart wrote:
>
>>> So it's either all or nothing.
>>
>> No, it's got lots of configuration options between "all" and "nothing".
>> -pedantic doesn't even come close to "nothing". You have to add at least
>> -Wall to get a decent collection of warnings, and certain kinds of
>> errors aren't even noticed unless you have a sufficiently high
>> optimization level. That's because the higher optimization levels
>> require it to do a more careful analysis of the code, and as a result of
>> that analysis it becomes capable of detecting some errors that are too
>> subtle for it to notice normally. Some people swear by -Wextra, but
>> that's going a little too far for my tastes - which might give you a
>> hint as to why there's so many options. Of course, it's a hint you're
>> inherently incapable to receiving,.
>>
>> It's only because your code routinely and seriously violates the C
>> standard that -pedantic seems like it rejects almost everything.
>
> If I compile one of my generated files with -pedantic, I get 14000 lines
> of warnings. From what I can see, there are two kinds:
>
> (1) Conversion between function pointers and void*

Of course that gives a diagnostic - it is undefined behaviour. You
can't assume that function pointers and data pointers have the same
size. (And before you complain about "hypothetical" or "dinosaur"
compilers, there are processors in use today, with new chips developed
regularly, where function and data pointers are different sizes.)

You can turn off this warning, like you can with most warnings in gcc,
with a specific flag.

-Wno-incompatible-pointer-types

(Disclaimer - I haven't tested this one. Maybe
"-Wno-cast-function-type" is the right choice.)

Of course you should not normally disable this warning - of preference
you should fix the code. Only use it if it is not your code and you are
sure your targets have the same size of pointers.

As a better alternative, use type "void (*) (void)" for a general
function pointer. gcc views it as the equivalent of "void *" for data
pointers. (The C standards don't have this as a general function
pointer, because different types of function pointers can have different
sizes in C. But all gcc targets have consistent sizes of function
pointers.)

>
> (2) Problems with pointer signedness, because I use 'unsigned char' for
> all my char types and string constants, while gcc uses 'char' with
> unspecified sign.

Again, the compiler warns you because this is undefined behaviour in C.
(Haven't we just been through this in another thread?).

And again, you can disable this warning:

-Wno-pointer-sign

This is a separate warning, because it is more likely people would want
to disable it - pointers to types which differ only in sign are
incompatible, but usually mixes will work as expected.

Remember that you can avoid command-line options here by:

#ifdef __GNUC__
#pragma GCC diagnostic ignored "-Wpointer-sign"
#endif


You can also add new warnings or errors by pragmas, such as:

#pragma GCC diagnostic error "-Wmissing-prototypes"


>
> So as far as I am concerned,there are two warnings. (Since usually
> fixing one of 2000 equal warnings, will also fix the other 1999).

I'd imagine you would have to fix the errors a great many times here.
If you had used a typedef for your generic function pointer type, you'd
perhaps only have had to change it in one place - but don't let that
ruin your prejudice against typedefs.

>
> But is (2) really that serious a violation? To fix it, I would have to
> put casts in front of every string constant, and everywhere I interface
> to external C functions that use char-based parameters. That might shut
> it up, but it will also hide any genuine type errors that might slip
> past my translator.

It is a violation of the C standards - so if you are trying to write
standard C, it /is/ a serious violation. But for practical C on many
targets, it will not cause a problem. You have to choose the level of
portability you are aiming at, and pick flags accordingly.

>
> If I add -Wall and _Wextra, I get 3000 more lines of warnings. Along the
> lines of 'label defined but not used' or 'unused variable'. Again, are
> these really serious violations?

In finished manually written code, a variable that is unused is almost
certainly a bug in the code. (And any labels at all, outside of
switches, are suspicious.) Unused variables are not violations of the C
standards in any way - the warnings are to tell you you've probably got
something wrong in your code. Under what circumstances would it make
sense to declare a variable, and then not use it?

For generated code, common generation patterns might lead to unused
variables and labels. So then you might want to turn off these warnings
explicitly. (/Please/ tell me you are able to find the correct gcc
flags for this yourself.)

It is not uncommon to have unused variables, functions, etc., while in
the middle of development.

David Brown

unread,
Aug 27, 2018, 4:19:54 AM8/27/18
to
I think you probably have a more accurate understanding than I do of
what counts as "conforming" for both compilers and programs. What I am
trying to get at here is that even with "-std=cNN -pedantic", gcc will
accept (without complaint) extensions that do not conflict with the
standards. Thus you can use "__typeof__", but not "typeof". You can't
have empty braces in an initialiser, because that conflicts with the
syntax given in the standards. But if that is fine within the
definition of "conforming compiler" then I agree with you that gcc aims
to be 100% conforming with those options.


(I believe all the C11 features are there - baring bugs, of course. The
development version even has a "-std=c17" option, but since C17 has no
changes except for defect corrections, and these are applied
retrospectively to C11 (and any other standards for which they are
relevant), "-std=c17" is identical to "-std=c11" except for the value of
__STDC_VERSION__.)


>> I don't think a "conforming C compiler" must diagnose /all/ violations
>> of syntax rules and constraints - just those that require a diagnostic.
>> Syntax rules usually can be fully checked, but there are lots of
>> constraints for which the compiler cannot check at compile-time.
>
> You corrected this in a followup.
>

I'm glad to hear I didn't get my correction wrong too!

David Brown

unread,
Aug 27, 2018, 4:36:25 AM8/27/18
to
I think you have to be careful to say what you mean by "compiling as C".

With "-std=c11", gcc will (baring bugs) compile any valid C11 program
correctly. It will also accept gcc extensions, as long as they don't
conflict with valid code. Thus it will accept empty braces in
initialisers - no valid C11 program would have that construct, so there
is no problem accepting it as an extension.

With "-std=c11 -pedantic", gcc will give all the diagnostics it has to,
and reject (as best it can) programs that are not valid C11.

So "-std=cNN" is about compiling programs as C. The "-pedantic" flag is
about rejecting programs that are not C.

David Brown

unread,
Aug 27, 2018, 5:05:46 AM8/27/18
to
On 27/08/18 03:12, Bart wrote:
> On 27/08/2018 00:59, james...@alumni.caltech.edu wrote:
>> On Sunday, August 26, 2018 at 4:27:40 PM UTC-4, Bart wrote:
>
>>> But presumably, with any of these three options, gcc is compiling actual
>>> C, and not gnuC, yes?
>>
>> How can it be compiling it as C code if the compiler fails to produce
>> diagnostics that the C standard specifies as mandatory? It is, after
>> all, precisely the absence of those diagnostics that you're complaining
>> about, isn't it? So how can you simultaneously treat the absence of
>> those diagnostics as unimportant?
>
> Take this file:
>
> int fn(void) {return;}
>
> If I use my compiler WITH NO OPTIONS AT ALL it says:
>
> Return value needed on line 1
>
> If I use 'gcc -std=c11 -pedantic -Wall -Wextra' then all I get is a
> warning. I have to add even more stuff to make it an error (and this can
> be a serious one as garbage would be returned or it could even crash).
>

A "return" in a non-void function needs a diagnostic. Your compiler
gives a diagnostic, gcc gives a diagnostic. It is not the compiler's
fault that you have trouble with that.

Note that the very similar case of:

int fn(void) { }

/is/ allowed in C, and needs to be supported by conforming compilers
(though they can give a non-fatal diagnostic message).

(I'd be happy that this sort of thing was a fatal error message. But
gcc is not made for me alone.)


> If I give it:
>
> f() {fred(10);}
>
> again no errors from gcc, only warnings.

It is legal C. It is not good, modern C, but it is legal. Conforming
compilers have to accept it.

> However I get an error here:
>
> f() {malloc(10,20,30);}
>
> not because malloc is undefined, but because there are too many
> parameters. Now, how does it know about malloc, since I haven't declared
> it? Is it allowed to have knowledge of stdlib.h when you haven't
> included stdlib.h?
>

The compiler knows about malloc because it is a standard function. I
think you /may/ be right that it should not use that knowledge unless
<stdlib.h> has been included. A warning would be allowed, but not an
error, I think.

> But back to the errors:
>
> f() {fred(); fred(10,20,30);}
>
> Again, just warnings. FFS, there are at least four things wrong with
> that program! And I'm not talking about initialised unsigned char string
> from non-signed bytes either.
>
> My attitude to these things seems to be completely at odds with anyone
> else's. Some things are obviously wrong; you don't need to give a
> compiler a raft of options for it to tell you that. Such a program MUST
> fail even without any options.
>

Your attitude is partly at odds with other people, and partly in
agreement. Your problem, however, is that you fail to see the nuances
here and are looking at everything in black and white.

Pretty much everyone here agrees that using functions without prototypes
is a bad thing in the code. (I know of only one person here, amongst
those whose opinion is respected, who has argued that it can sometimes
be a good thing.) Pretty much everyone would be happy if their compiler
made such things fatal errors. And I expect that most /use/ their
compilers in a way that these are at least warnings (which they do not
ignore), or fatal errors.

However, pretty much everyone here understands why these are /not/
errors by default in compilers - the standards say they are legal. They
also understand /why/ the standards say they are legal - existing code
uses those constructs.

You can't change the past. You can only choose how you go forward. So
conforming compilers let past code compile as before - and good
compilers let you choose to have better checking for future code.

When you are writing a one-man compiler for your own use, you don't have
to worry about existing code, nor about conformance to standards. You
can make such bad code an error if you like. But other compilers can't
do that.


a...@littlepinkcloud.invalid

unread,
Aug 27, 2018, 5:10:55 AM8/27/18
to
james...@alumni.caltech.edu wrote:
> On Sunday, August 26, 2018 at 2:01:54 PM UTC-4, Bart wrote:
>> On 26/08/2018 18:18, james...@alumni.caltech.edu wrote:
>> > On Sunday, August 26, 2018 at 12:13:43 PM UTC-4, Bart wrote:
>>
>> >> Using -pedantic is an extreme measure where a program has to be perfect
>> >> to pass without warnings, so that you have to fix things that are
>> >> harmless, and that are generally accepted elsewhere.
>> >
>> > Code that is far less than perfect can easily pass -pedantic. Code has
>> > to be as poorly written as yours for gcc -pedantic to have serious
>> > problems with it.
>>
>> So why would anyone have any objection to (1) having -pedantic be turned
>> on by default; (2) having any transgressions always be fatal errors by
>> default?
>
> I don't know for sure - why don't you ask the question of someone who
> might actually be able to answer it, in a gcc-oriented forum?

I think I probably qualify. GCC development is a part of the GNU
Project, aiming to improve the compiler used in the GNU system. The
first goal of GCC in the Mission Statement is supporting the goals of
the GNU project, as defined by the FSF.

https://gcc.gnu.org/gccmission.html

GNU C is the variant of C used by the GNU project.

> It's only because your code routinely and seriously violates the C
> standard that -pedantic seems like it rejects almost everything.

Andrew.

Tim Rentsch

unread,
Aug 27, 2018, 6:02:03 AM8/27/18
to
james...@alumni.caltech.edu writes:

> I don't use either of [-Werror or -pedantic-errors] because doing
> so would prevent me from using my own judgment about warnings
> triggered by things for which a diagnostic is not mandatory.

With reference only to -pedantic-errors, are you aware of any
constructions that would be flagged under -pedantic-errors
that you would choose not to be an error? If so can you say
what they are? If you don't know of any, do you have reason
to think there might be some even though you don't know what
they are? If you do what is (or are) the reasons?

Richard Damon

unread,
Aug 27, 2018, 6:45:05 AM8/27/18
to
On 8/27/18 4:19 AM, David Brown wrote:

> I think you probably have a more accurate understanding than I do of
> what counts as "conforming" for both compilers and programs. What I am
> trying to get at here is that even with "-std=cNN -pedantic", gcc will
> accept (without complaint) extensions that do not conflict with the
> standards. Thus you can use "__typeof__", but not "typeof". You can't
> have empty braces in an initialiser, because that conflicts with the
> syntax given in the standards. But if that is fine within the
> definition of "conforming compiler" then I agree with you that gcc aims
> to be 100% conforming with those options.
>

The use of __ symbols in extensions doesn't make an implementation
non-conforming as the use of __ in a symbol is reserved for the
implementation, and this reservation is outside a constraints section,
thus not needing a diagnostic.

Bart

unread,
Aug 27, 2018, 7:27:41 AM8/27/18
to
On 27/08/2018 09:36, David Brown wrote:

> So "-std=cNN" is about compiling programs as C. The "-pedantic" flag is
> about rejecting programs that are not C.
>

So someone uses -std=c99 without -pedantic, and it compiles all the same
extensions, but throws out ones like anonymous unions.

What's the point of that then? It won't guarantee that compiled code
will work with another C99 compiler, as it might still have local
extensions.

(And it the case of -std-c90, it will also throw out the use of //
comments, which are universally supported in any compiler of the last 25
years. Unless perhaps // comments are also a local extension in this
compiler...)

--
bart

Bart

unread,
Aug 27, 2018, 7:40:53 AM8/27/18
to
I've already abandoned it. Actually I think I only spent one year
writing it around 2012, and even then I had to use it via a syntax
wrapper to make it less painful.

Now I'm only using it as an intermediate language and there the problems
are showing up. (Some compilers don't like '$' in names. Some don't like
long string constants. Some need __attribute__(dllimport). etc etc. Plus
all this UB business.)

But I still have to use interfaces specified in C. And I'm still
maintaining my own C compiler but as a private project. One which is my
first choice to compile short programs as it will tell me what's what
without any arm-twisting.

Note that maintaining a C compiler is not the same thing as writing C
code; the compiler isn't written in C.

--
bart

Kenny McCormack

unread,
Aug 27, 2018, 7:49:16 AM8/27/18
to
In article <6c74b9ac-af10-42e9...@googlegroups.com>,
<james...@alumni.caltech.edu> wrote:
...
>Lots of people have reasons, both valid and invalid, for deliberately
>writing code that would be rejected by -pedantic.

I'm curious. What would say is an "invalid" reason for using GCC
extensions? Can you give a concrete example?

>That wouldn't be a reasonable approach for
>someone with your level of understanding.

Ouch. Low blow! Throwin' the shade, are we?

>Of course, it's a hint you're
>inherently incapable to receiving,.

Ouch. Low blow!
So much for civility on this board...

--
The randomly chosen signature file that would have appeared here is more than 4
lines long. As such, it violates one or more Usenet RFCs. In order to remain
in compliance with said RFCs, the actual sig can be found at the following URL:
http://user.xmission.com/~gazelle/Sigs/CLCtopics

James Kuyper

unread,
Aug 27, 2018, 8:00:02 AM8/27/18
to
On 08/27/2018 04:19 AM, David Brown wrote:
...
> I think you probably have a more accurate understanding than I do of
> what counts as "conforming" for both compilers and programs.

The C standard defines a program as conforming if it can be accepted by
at least one fully conforming implementation (4p7). The only feature a
program can contain that makes rejecting the program mandatory for a
fully conforming implementation of C is a #error directive that survives
conditional compilation (4p4). Therefore, it would be possible for a
fully conforming implementation to accept all other programs - and for
all I know, someone might have already created such a program, if only
as an obscure kind of joke. Therefore, just about anything qualifies as
a conforming C program - including the Code of Hammurabi, in the
original Akkadian. This definition of "conforming program" was, like
many other similarly useless things, the result of a political compromise.

The rules for a conforming implementation of C are much stricter, though
still far too lax, especially by BartC's standards (but even by mine).

What I am
> trying to get at here is that even with "-std=cNN -pedantic", gcc will
> accept (without complaint) extensions that do not conflict with the
> standards. Thus you can use "__typeof__", but not "typeof". You can't
> have empty braces in an initialiser, because that conflicts with the
> syntax given in the standards. But if that is fine within the
> definition of "conforming compiler" then I agree with you that gcc aims
> to be 100% conforming with those options.

You can have empty braces in an initializer - that's only a syntax
error, so the only requirement on an fully conforming implementation is
that it issue at least one diagnostic for such a program (which could be
a warning. It could also be "Congratulations for using our extensions to
C"). The implementation is not required to accept a program containing
syntax errors - but neither is it required to reject such a program (in
fact, a pre-processing syntax error could give an implementation all the
permission it needs to ignore a #error directive).
If it does accept such a program, and if you decide to try to execute
the resulting program, te behavior is undefined - but that could include
handling the empty braces as if they were equivalent to "{0}", and
handling the rest of the program normally. Alternatively, they could be
handled the same as if there were no initializer. As long as the
required diagnostic is concerned, either of those extensions could be
offered as a fully conforming extension to C (4p6) - it would have no
effect on strictly conforming code.

This is precisely why it's very wrong-headed to treat error messages as
more important than warning messages - they both qualify as diagnostics,
and a warning might be the only warning you receive about a syntax error
or constraint violation.

James Kuyper

unread,
Aug 27, 2018, 8:10:51 AM8/27/18
to
On 08/27/2018 04:36 AM, David Brown wrote:
...
> I think you have to be careful to say what you mean by "compiling as C".
>
> With "-std=c11", gcc will (baring bugs) compile any valid C11 program
> correctly. It will also accept gcc extensions, as long as they don't
> conflict with valid code. Thus it will accept empty braces in
> initialisers - no valid C11 program would have that construct, so there
> is no problem accepting it as an extension.
>
> With "-std=c11 -pedantic", gcc will give all the diagnostics it has to,
> and reject (as best it can) programs that are not valid C11.
>
> So "-std=cNN" is about compiling programs as C. The "-pedantic" flag is
> about rejecting programs that are not C.

From my point of view, accepting code that C requires be accepted, and
diagnosing problems that C requires be diagnosed, are both equally
important requirements before you can properly say it's being compiled
as C code. Rejecting code that C requires to be rejected is also
important, but I can't claim it's as important as the other two aspects:
#error, while useful, isn't a commonplace construct, at least not in my
code.

David Brown

unread,
Aug 27, 2018, 8:12:34 AM8/27/18
to
On 27/08/18 13:27, Bart wrote:
> On 27/08/2018 09:36, David Brown wrote:
>
>> So "-std=cNN" is about compiling programs as C. The "-pedantic" flag is
>> about rejecting programs that are not C.
>>
>
> So someone uses -std=c99 without -pedantic, and it compiles all the same
> extensions, but throws out ones like anonymous unions.
>
> What's the point of that then? It won't guarantee that compiled code
> will work with another C99 compiler, as it might still have local
> extensions.

"-std=c99" is for compiling programs that conform to C99. You use it if
you have code that is C99 - which might not compile with "-std=gnu99"
because it happens to use "typeof" as a function name, or some other
code that is valid C99 but conflicts with gnu99 extensions.

"-std=c99 -pedantic" helps check that the code is C99 conforming.

Even if the code compiles warning-free with gcc "-std=c99 -pedantic",
that does not mean it will work with another C99 compiler. It can still
contain extensions, but these have to use either the "__extension__"
keyword, or other double-underscore names (like "__typeof__"). The
manual recommends that you don't use these features, because that would
make the code incompatible with other compilers - but they may be used
in header files which are already implementation-specific. It is no
problem if, say, the <stdlib.h> uses a gcc-specific "__attribute__" -
that won't affect the portability of your own code.

And of course most (all?) of the other compilers you use play fast and
loose with the standards, mixing bits and pieces from the different C
standards and their own extensions, misinterpretations, or limitations.

All this means is that if you want to write portable code, you need to
know what is allowed in C and what is not - you can't just rely on a
tool to do all the checking for you. The tool is a help - a big help -
but it is not a substitute for your own knowledge.

>
> (And it the case of -std-c90, it will also throw out the use of //
> comments, which are universally supported in any compiler of the last 25
> years. Unless perhaps // comments are also a local extension in this
> compiler...)
>

// comments are not part of C90. They are a syntax error for any
conforming C90 compiler (including gcc -std=c90 -pedantic). If you want
your code to be proper C90 code, then don't use // comments. If you
want to use // comments, don't insist on strict C90 modes.


James Kuyper

unread,
Aug 27, 2018, 8:19:19 AM8/27/18
to
On 08/27/2018 05:05 AM, David Brown wrote:
...
> The compiler knows about malloc because it is a standard function. I
> think you /may/ be right that it should not use that knowledge unless
> <stdlib.h> has been included. A warning would be allowed, but not an
> error, I think.

Like all identifiers with external linkage declared in the C standard
headers, "malloc" is a reserved identifier when used with external
linkage, regardless of whether or not you #include the relevant header
(7.1.3p1). If it had been declared with internal linkage, then the
implementation would be required to pay attention to how it was actually
declared. However, if that's not the case, since the only way 'malloc'
could be used with external linkage and defined behavior is if it refers
to the standard library function, I think an implementation is entitled
to validate a use of an undeclared malloc() against that library's
declaration for that function, even if you haven't told it to load that
declaration.

Anton Shepelev

unread,
Aug 27, 2018, 8:19:50 AM8/27/18
to
David Brown:

>All this means is that if you want to write portable code,
>you need to know what is allowed in C and what is not - you
>can't just rely on a tool to do all the checking for you.
>The tool is a help - a big help - but it is not a
>substitute for your own knowledge.

Why not? Ensurance of standard-conforming, portable code
seems a job well fit for a compiler.

--
() ascii ribbon campaign - against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]

David Brown

unread,
Aug 27, 2018, 9:08:06 AM8/27/18
to
On 27/08/18 13:40, Bart wrote:
> On 27/08/2018 03:09, james...@alumni.caltech.edu wrote:
>> On Sunday, August 26, 2018 at 8:50:54 PM UTC-4, Bart wrote:
>
>
>>> The exact same original sources translate to x64 native code with none
>>> of the problems I get from doing it in C.
>>
>> Then I strongly recommend going with x64 native code and abandoning a
>> language you're tempermentally incapable of learning to use correctly.
>>
>
> I've already abandoned it. Actually I think I only spent one year
> writing it around 2012, and even then I had to use it via a syntax
> wrapper to make it less painful.
>
> Now I'm only using it as an intermediate language and there the problems
> are showing up. (Some compilers don't like '$' in names. Some don't like
> long string constants. Some need __attribute__(dllimport). etc etc. Plus
> all this UB business.)
>

All the problems you are seeing are of your own manufacturing, because
you insist on bizarre restrictions that simply do not work with reality.

It does not matter how you think things "should" work in the world of C.
What matters is how things /do/ work. Accept that, and all your
invented troubles will be solvable in a straight-forward manner.

David Brown

unread,
Aug 27, 2018, 9:12:54 AM8/27/18
to
Good point. Thank you.

David Brown

unread,
Aug 27, 2018, 9:18:25 AM8/27/18
to
On 27/08/18 14:19, Anton Shepelev wrote:
> David Brown:
>
>> All this means is that if you want to write portable code,
>> you need to know what is allowed in C and what is not - you
>> can't just rely on a tool to do all the checking for you.
>> The tool is a help - a big help - but it is not a
>> substitute for your own knowledge.
>
> Why not? Ensurance of standard-conforming, portable code
> seems a job well fit for a compiler.
>

I am sure it would be possible to get closer to such a tool, but gcc is
not that tool at the moment. (It covers most things - with the right
flags - but does not aim to cover everything.) Adding a warning on any
gcc extension keywords (like __extension__, __typeof__, etc.) outside of
system headers would be another big step on the way there. But this is
not something the gcc developers see as an important area of
development. From the manual's description of "-pedantic":

> Some users try to use -Wpedantic to check programs for strict ISO C
> conformance. They soon find that it does not do quite what they want:
> it finds some non-ISO practices, but not all—only those for which ISO
> C requires a diagnostic, and some others for which diagnostics have
> been added.

> A feature to report any failure to conform to ISO C might be useful
> in some instances, but would require considerable additional work and
> would be quite different from -Wpedantic. We don’t have plans to
> support such a feature in the near future.


Bart

unread,
Aug 27, 2018, 9:47:52 AM8/27/18
to
On 27/08/2018 02:53, Richard Damon wrote:
> On 8/26/18 8:50 PM, Bart wrote:

>> (1) Conversion between function pointers and void*

> (1) You should know that function pointers and void* data pointers are
> not compatible, on some machines they are vastly different sizes.

The thing with function pointers and void*, is because I use void* in
the source language to represent a generic function pointer.

Apparently C uses void(*)(void) for this purpose, although it appears to
still require a cast to that pointer type.

I would also have used that, except that (1) a cast is still need; (2)
such a pointer could be also be a valid function pointer type, it is not
a generic type.

So in the source language, I would prefer to still use void* for this
purpose, which also removes the need for casts to convert any function
address to the generic form.

Given that, the C translator at some point will see a cast like this but
in intermediate representation:

(void*)malloc # may also be implicit

and needs to decide how to represent that as C. Up to know I've left it
as that, as it is likely to work perfectly on my intended targets
(namely x86 and ARM), and C compiler didn't mind (mine doesn't).

But the pedants here objected very strongly to it.

What I've used in the past, if linking to such C code, was to specify
recommended ways of compiling it (eg. gcc program.c). And that seemed to
work fine.

But with the amount of feedback I've got here (and, frankly, abuse and
undisguised insults), what I'm doing now is not to publish such code at all.

The primary reason for doing this is so that I can have my applications
running 20-50% faster by putting them through gcc's optimiser, which
requires them it to be in C form.

Since that appears to work exactly as I wanted, I don't need to waste
time hacking at the C translator to achieve perfectly compilable output,
just to satisfy a few perfectionists. (It's not as though as they would
do that for me.)

--
bart
> (2) char IS a different type than signed char and unsigned char.

THAT's what should be addressed. I couldn't believe it when I learned
about it.

Then people can get on with more worthwhile things than grappling with
artificially created and perpetuated issues.

--
bart

Bart

unread,
Aug 27, 2018, 9:57:33 AM8/27/18
to
On 27/08/2018 12:59, James Kuyper wrote:

> You can have empty braces in an initializer - that's only a syntax
> error,

ONLY a syntax error?

so the only requirement on an fully conforming implementation is
> that it issue at least one diagnostic for such a program (which could be
> a warning. It could also be "Congratulations for using our extensions to
> C"). The implementation is not required to accept a program containing
> syntax errors - but neither is it required to reject such a program (in
> fact, a pre-processing syntax error could give an implementation all the
> permission it needs to ignore a #error directive).

I took a program that compiled perfectly fine using -std=c11.

I then deliberately removed a semicolon. The result was 400 lines of
error messages (on a program of 900 lines).

THIS is why I usually stop at the first syntax error. That pinpoints the
problem, I can fix it and move onto the next.

But, surely there will be a gcc option to do the same? Indeed there is:
-Wfatal-errors. Yet another option to teach gcc how to compile code.

A few more and, you never know, gcc might be just as good as mine in
making sensible choices in compiling programs!

> If it does accept such a program

It shouldn't. With such a preoccupation with correct, conforming code in
this group, it is mind-boggling that anyone can entertain the idea of
code with syntax errors actually being turned into a running program.

So initialising an array of unsigned char with a series of plain
character codes is a complete no-no as it violates everything in the C
standard.

But a compiler making an executable out of:

spam() {spam(),spam(spam),spam("spam");}

? No problem!

With my compiler, it is /impossible/ for this program to pass as it is.
With gcc, it is eminently possible, it just needs to find an entry
point, eg:

spam() {spam(),spam(spam),spam("spam");}

main(){spam();}

When I ran this (building with 'gcc -std=c11 -pedantic -Wall -Wextra'),
it crashed. What a surprise.

Perhaps you can see now why I have the opinions I do about gcc.

--
bart

David Brown

unread,
Aug 27, 2018, 10:22:34 AM8/27/18
to
On 27/08/18 15:47, Bart wrote:
> On 27/08/2018 02:53, Richard Damon wrote:
>> On 8/26/18 8:50 PM, Bart wrote:
>
>>> (1) Conversion between function pointers and void*
>
>> (1) You should know that function pointers and void* data pointers are
>> not compatible, on some machines they are vastly different sizes.
>
> The thing with function pointers and void*, is because I use void* in
> the source language to represent a generic function pointer.

Then you can't translate "void*" in your source language directly to
"void*" in C.

If your source language had a type called "char" that held UTF-32
characters, would you expect to translate it directly to "char" in C?
Of course not. So why are you using a type in C that does not do what
the type in your source language wants?

If only there were a way to make types in C that do what you want here.
Oh, wait, there /is/ a way. If you want to know, ask - if you prefer
to keep writing incorrect code and complaining when your compiler points
it out, then I guess you can do that too.

>
> Apparently C uses void(*)(void) for this purpose, although it appears to
> still require a cast to that pointer type.

Where did you get the idea that C uses "void(*)(void)" for this purpose?
If your answer is that you think I wrote it, please go back and re-read
my post that mentioned it.

>
> I would also have used that, except that (1) a cast is still need; (2)
> such a pointer could be also be a valid function pointer type, it is not
> a generic type.

This is /generated/ C code we are still talking about, not manually
written C code? If that's the case, my answers are (1) So what? and (2)
So what?

>
> So in the source language, I would prefer to still use void* for this
> purpose, which also removes the need for casts to convert any function
> address to the generic form.

It's your language, you can call your types whatever you want there.
But you can't call them something and expect that this somehow makes
them the same as a C type of the same name.

>
> Given that, the C translator at some point will see a cast like this but
> in intermediate representation:
>
> (void*)malloc # may also be implicit
>
> and needs to decide how to represent that as C. Up to know I've left it
> as that, as it is likely to work perfectly on my intended targets
> (namely x86 and ARM), and C compiler didn't mind (mine doesn't).
>
> But the pedants here objected very strongly to it.

We have this nasty habit of preferring C code to be correct C code - or
if it is implementation-specific code, we prefer it to be noted that it
is implementation-specific.

>
> What I've used in the past, if linking to such C code, was to specify
> recommended ways of compiling it (eg. gcc program.c). And that seemed to
> work fine.

You have complained endlessly about how you could /not/ do that, when
countless people have told you that this is a valid method as long as
you specify a /sensible/ way of compiling the code (i.e., not blindly
relying on default behaviour that everyone agrees is inappropriate).

>
> But with the amount of feedback I've got here (and, frankly, abuse and
> undisguised insults), what I'm doing now is not to publish such code at
> all.

When you say stupid things, helpful people will tell you you are being
stupid. (That is /not/ the same thing as saying that you /are/ stupid.)
When you demonstrate stubborn and unrelenting ignorance of some aspects
of C, no matter how often you are corrected and given help and advice,
you can't expect people to be kind about it. Personally, I like to make
it entirely clear when you are making the same mistakes again and again
- while at the same time I try to give you help and encourage better
ways of handling the problem.

The way to stop people telling you you are doing daft things in your C
code is to listen to others and stop doing daft things - not to stop
writing C code.

anti...@math.uni.wroc.pl

unread,
Aug 27, 2018, 10:30:06 AM8/27/18
to
Yep, you have infinite recursion and you get stack overflow.
Try:

spam2() {}

spam() {spam2(),spam2(spam),spam2("spam");}

main(){spam();}

That way there is no recursion and it works OK. Definitely
not the way to write new code. But there is "working code"
using constructs written in such style. Most is probaly
highly guarded "intelectual property" of some company.
Owners of such code still have enough influence to make
it legal C.

--
Waldek Hebisch

David Brown

unread,
Aug 27, 2018, 10:34:06 AM8/27/18
to
On 27/08/18 15:57, Bart wrote:
> On 27/08/2018 12:59, James Kuyper wrote:
>
>> You can have empty braces in an initializer - that's only a syntax
>> error,
>
> ONLY a syntax error?

Yes - it is a very minor syntax error, with a clear implementation.

>
> so the only requirement on an fully conforming implementation is
>> that it issue at least one diagnostic for such a program (which could be
>> a warning. It could also be "Congratulations for using our extensions to
>> C"). The implementation is not required to accept a program containing
>> syntax errors - but neither is it required to reject such a program (in
>> fact, a pre-processing syntax error could give an implementation all the
>> permission it needs to ignore a #error directive).
>
> I took a program that compiled perfectly fine using -std=c11.
>
> I then deliberately removed a semicolon. The result was 400 lines of
> error messages (on a program of 900 lines).
>
> THIS is why I usually stop at the first syntax error. That pinpoints the
> problem, I can fix it and move onto the next.

Sometimes a minor change will through the whole compiler out of
synchronisation, leading to an avalanche of errors. You see that with
any tool, and any language. Getting back in sync so that the tool can
figure out where the real problem lies is a hard problem, and tools vary
about how well they do that. (gcc has got better at this - equally,
that implies that old versions are not as good as they could have been.)

>
> But, surely there will be a gcc option to do the same? Indeed there is:
> -Wfatal-errors. Yet another option to teach gcc how to compile code.
>
> A few more and, you never know, gcc might be just as good as mine in
> making sensible choices in compiling programs!
>

You can use "-Wfatal-errors" if you like. Personally, I usually prefer
to have all the errors but use an IDE so that I can quickly go to the
first error on the list (or whichever other error I want to concentrate
on). I find it helpful to have a full list. But you pick the
development practices that fit you best - gcc gives you the switches to
choose.

>> If it does accept such a program
>
> It shouldn't. With such a preoccupation with correct, conforming code in
> this group, it is mind-boggling that anyone can entertain the idea of
> code with syntax errors actually being turned into a running program.
>
> So initialising an array of unsigned char with a series of plain
> character codes is a complete no-no as it violates everything in the C
> standard.
>

Initialising an array of unsigned char with a string literal is allowed.
Initialising a pointer of one type with a pointer of an incompatible
type is not.


> But a compiler making an executable out of:
>
> spam() {spam(),spam(spam),spam("spam");}
>
> ? No problem!
>
> With my compiler, it is /impossible/ for this program to pass as it is.
> With gcc, it is eminently possible, it just needs to find an entry
> point, eg:
>
> spam() {spam(),spam(spam),spam("spam");}
>
> main(){spam();}
>
> When I ran this (building with 'gcc -std=c11 -pedantic -Wall -Wextra'),
> it crashed. What a surprise.
>
> Perhaps you can see now why I have the opinions I do about gcc.
>

Garbage in, garbage out.

Learn the rules of C. Learn to use your tools. Understand that C is a
very flexible language - you have plenty of scope for writing nonsense.
The key to the whole business is simply not to write nonsense. It
really is not as hard as you make it out to be.

Bart

unread,
Aug 27, 2018, 11:45:50 AM8/27/18
to
On 27/08/2018 15:22, David Brown wrote:

>> Apparently C uses void(*)(void) for this purpose, although it appears to
>> still require a cast to that pointer type.
>
> Where did you get the idea that C uses "void(*)(void)" for this purpose?


ME [12-AUG-18 Mixed Arithmetic]:
>> How would YOU rewrite a table like this of mixed function pointers:
>>
>> void *table[] = {malloc, realloc, free, printf, puts};

BEN:
> typedef void func(void);
>
> func *table[] = {
> (func *)malloc, (func *)realloc, (func *)free, (func *)printf,
(func *)puts
> };


>>
>> I would also have used that, except that (1) a cast is still need; (2)
>> such a pointer could be also be a valid function pointer type, it is not
>> a generic type.
>
> This is /generated/ C code we are still talking about, not manually
> written C code?

The cast has to be in the original source.

If that's the case, my answers are (1) So what? and (2)
> So what?

It's like using char* to do the job of void*.

I'm surprised you don't get that.

> It's your language, you can call your types whatever you want there.
> But you can't call them something and expect that this somehow makes
> them the same as a C type of the same name.

In modern processors there's no reason why you can't cast a void* to
function pointer or vice versa, as they are almost certain to be the
same size.

Bizarrely, C allows casting between function pointers and ints, but not
between function pointers and ordinary pointers!

Unless the ordinary pointer has the value 0, then casting between a
function pointer and (void)*0 IS allowed.

Who makes up this stuff?

(BTW I think I've just found a way around the problem: you can cast from
from pointer to function pointer VIA an int cast. Although it will need
to be an int matching the size of the pointers of either side. (If the
two pointer types are a different size, then there's a genuine problem.)

So, apparently, it can be done. In which case why the need to go to such
lengths?)

> The way to stop people telling you you are doing daft things in your C
> code is to listen to others and stop doing daft things - not to stop
> writing C code.

This group is more like a secret society than anything else. with lots
of arcane, made-up rules, initiation procedures and a hierarchy of
members. Plus all their complicated tools with their 1001 settings.
[More than that actually. Anyone outside that clique, have a read of
Asimov's story /Profession/ to get a better idea of what I'm talking about.]

People just want to run their low level programs on their machine of
choice; why do they have to do battle with the C language, C compilers,
C options and the clc cartel?

This is why there need to be modern alternatives - not the even more
bloated ones - that don't consist of 90% ancient baggage.

--
bart

Bart

unread,
Aug 27, 2018, 12:02:06 PM8/27/18
to
On 27/08/2018 16:45, Bart wrote:

> This group is more like a secret society than anything else.

[TBF, stackoverflow seems worse...]

I think this will be my last post in the group.

Anyone wanting to continue a discussion (not insults) can email me
privately as bart4858 on gmail, or publicly on comp.lang.misc.

I will monitor the group for a bit longer. If there's something I really
have to reply to, I will try and do it on comp.lang.misc (which needs
some traffic anyway).

I doubt I will need any further help with C.

bart.

Keith Thompson

unread,
Aug 27, 2018, 12:10:52 PM8/27/18
to
David Brown <david...@hesbynett.no> writes:
> On 27/08/18 02:50, Bart wrote:
[...]
>> (1) Conversion between function pointers and void*
>
> Of course that gives a diagnostic - it is undefined behaviour. You
> can't assume that function pointers and data pointers have the same
> size. (And before you complain about "hypothetical" or "dinosaur"
> compilers, there are processors in use today, with new chips developed
> regularly, where function and data pointers are different sizes.)

I agree that it's undefined behavior -- but gcc treats it as a
constraint violation, as I discussed elsewhere in this thread.
(It doesn't matter if you just avoid doing such conversions.)

[...]

> As a better alternative, use type "void (*) (void)" for a general
> function pointer. gcc views it as the equivalent of "void *" for data
> pointers. (The C standards don't have this as a general function
> pointer, because different types of function pointers can have different
> sizes in C. But all gcc targets have consistent sizes of function
> pointers.)

There's nothing gcc-specific about that. N1570 6.3.2.3p8:

A pointer to a function of one type may be converted to a pointer
to a function of another type and back again; the result shall
compare equal to the original pointer. If a converted pointer
is used to call a function whose type is not compatible with
the referenced type, the behavior is undefined.

In effect any function pointer type can be used as a generic function
pointer type (though there's no implicit conversion as there is with
void*). If you want to define a specific type to be used as a generic
function pointer type, you might consider a type that's never used
otherwise, so that you'll always get a warning if you try to use it
without a cast. For example:

typedef struct undefined *generic_function(struct undefined*);

An implementation could have different sizes for different function
pointer types, but the conversion requirement would make that awkward.

>> (2) Problems with pointer signedness, because I use 'unsigned char' for
>> all my char types and string constants, while gcc uses 'char' with
>> unspecified sign.
>
> Again, the compiler warns you because this is undefined behaviour in C.
> (Haven't we just been through this in another thread?).

If you convert between unsigned char* and char* without a cast, it's not
just undefined behavior. It's a constraint violation.

[...]

--
Keith Thompson (The_Other_Keith) ks...@mib.org <http://www.ghoti.net/~kst>
Working, but not speaking, for JetHead Development, Inc.
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"

Keith Thompson

unread,
Aug 27, 2018, 12:13:47 PM8/27/18
to
David Brown <david...@hesbynett.no> writes:
> On 27/08/18 08:53, Keith Thompson wrote:
[...]
>> Compilers are software, all software has bugs, therefore compilers have
>> bugs. Absolute 100% conformance may not be possible. The point is that
>> "gcc -std=cNN -pedantic" *attempts* to be conforming, and it comes
>> pretty close. (There may be a handful of C11 features that haven't been
>> implemented yet; I haven't checked lately.)
>
> I think you probably have a more accurate understanding than I do of
> what counts as "conforming" for both compilers and programs. What I am
> trying to get at here is that even with "-std=cNN -pedantic", gcc will
> accept (without complaint) extensions that do not conflict with the
> standards. Thus you can use "__typeof__", but not "typeof". You can't
> have empty braces in an initialiser, because that conflicts with the
> syntax given in the standards. But if that is fine within the
> definition of "conforming compiler" then I agree with you that gcc aims
> to be 100% conforming with those options.

N1570 4p6:
A conforming implementation may have extensions (including
additional library functions), provided they do not alter the
behavior of any strictly conforming program.

A program that uses __typeof__ is not strictly conforming, so using it
in an extension can be conforming.

Keith Thompson

unread,
Aug 27, 2018, 12:30:36 PM8/27/18
to
Bart <b...@freeuk.com> writes:
[...]
>> If it does accept such a program
>
> It shouldn't. With such a preoccupation with correct, conforming code in
> this group, it is mind-boggling that anyone can entertain the idea of
> code with syntax errors actually being turned into a running program.

You find it mind-boggling that so many of us understand what the C
standard actually says. You mistake descriptions of what it says for
opinions about what it should say.

> So initialising an array of unsigned char with a series of plain
> character codes is a complete no-no as it violates everything in the C
> standard.

No, this:
unsigned char arr[] = "hello";
is perfectly legal. See N1570 6.7.9p14. (unsigned char is a character
type.)

This:
unsigned char *p = "hello";
is a constraint violation. It does not "violate everything in the
C standard". It violates a single constraint. (N1570 6.7.9p11
refers to the constraints for simple assignment; the initializer
violates 6.5.16.1p1.)

Yes, this seems inconsistent. I won't waste my time explaining why.

> But a compiler making an executable out of:
>
> spam() {spam(),spam(spam),spam("spam");}
>
> ? No problem!

The standard only forbids successful compilation in the presence of a
#error directive. For all other errors, the standard permits an
executable to be generated (in some cases after a required diagnostic).
It is a fact that this is what the standard says. We're all aware of
your opinion about that fact.

> With my compiler, it is /impossible/ for this program to pass as it is.
> With gcc, it is eminently possible, it just needs to find an entry
> point, eg:
>
> spam() {spam(),spam(spam),spam("spam");}
>
> main(){spam();}
>
> When I ran this (building with 'gcc -std=c11 -pedantic -Wall -Wextra'),
> it crashed. What a surprise.
>
> Perhaps you can see now why I have the opinions I do about gcc.

gcc's behavior is conforming. If you had wanted gcc to reject that
program, you could have used -pedantic-errors rather than -pedantic.
Your stubborn refusal to learn how to use your tools is boring.

Keith Thompson

unread,
Aug 27, 2018, 12:34:05 PM8/27/18
to
anti...@math.uni.wroc.pl writes:
[...]
> Yep, you have infinite recursion and you get stack overflow.
> Try:
>
> spam2() {}
>
> spam() {spam2(),spam2(spam),spam2("spam");}
>
> main(){spam();}
>
> That way there is no recursion and it works OK. Definitely
> not the way to write new code. But there is "working code"
> using constructs written in such style. Most is probaly
> highly guarded "intelectual property" of some company.
> Owners of such code still have enough influence to make
> it legal C.

Your code contains constraint violations, since C99 dropped
implicit int. A conforming compiler must diagnose it, and may or
may not reject it.

If you add explicit return types to the functions, there is no
constraint violation, but the program's behavior is undefined.
spam2() is defined with no parameters; calling it with one or more
parameters has undefined behavior. It may happen to "work", which is
one of the infinitely many possible outcomes of undefined behavior.

Ben Bacarisse

unread,
Aug 27, 2018, 12:56:38 PM8/27/18
to
Richard Damon <Ric...@Damon-Family.org> writes:

Piggy-backing, here...

> (1) You should know that function pointers and void* data pointers are
> not compatible, on some machines they are vastly different sizes.

Also they may be the same size but simply refer to different address
spaces. The conversion is then less damaging (unless there is some sort
of segment normalisation going on) but pointless. You can't read from
it since all you'll get is data from the data address with the same
numerical value.

The key question to ask is why this conversion is being done. If it is
simply to store function pointers for later use as function pointers,
the code should use some common function pointer type like void
(*)(void), but if it is because the pointer is actually going to be used
as an object pointer, then all bets are off and you are looking at
highly implementation-specific code.

With machine generated code, it's possibly being done because the source
language as a common pointer type, so:

<snip>
> If you are generating code that depends on machine tricks (even if you
> think ALL machines you can think of targeting do it that way), then to
> use C as an intermediary language, you need to put the implementation
> into a mode that allows those tricks or generate code that doesn't need
> those tricks but follows the rules of the C Abstract machine. The C
> language allows for both if you use it right.

If the machine generated code needs to store all pointers in a common
type, you can do the conversion via (or indeed store the pointers as)
uintptr_t. That should give you no warnings, which is a plus or a minus
depending on how you use the generated C code!

--
Ben.

Ben Bacarisse

unread,
Aug 27, 2018, 1:49:29 PM8/27/18
to
Bart <b...@freeuk.com> writes:

> Take this file:
>
> int fn(void) {return;}
>
> If I use my compiler WITH NO OPTIONS AT ALL it says:
>
> Return value needed on line 1
>
> If I use 'gcc -std=c11 -pedantic -Wall -Wextra' then all I get is a
> warning.

You don't need those options, at least with a modern gcc

But why do keep going on about this? You should have posted a message
years ago saying that you'd prefer that some/many/all gcc warnings to be
errors. You'd have had a reply about how to change that and you could
choose to ignore or heed as you wish.

What are you hoping to achieve? If you want to change what gcc does,
this is not a good place to try to do it.

You don't use C anymore except as a generation target, so why do you
care what class of diagnostic is produced? Presumably you can't
generate int fn(void) {return;} without your translator already flagging
an error in the source.

> My attitude to these things seems to be completely at odds with anyone
> else's. Some things are obviously wrong; you don't need to give a
> compiler a raft of options for it to tell you that. Such a program
> MUST fail even without any options.

C has a long history. Before void, all functions "returned" something
in the sense that you could not say that they did not. Leaving off the
type was a common convention, but then an int return was assumed. So in
old C it was very common to a have "return;" in value-returning
functions because all functions were value-returning -- you just
declined to give a value to return!

Nowadays, provided you ask for at least -std=c99, compilers could (and
in my opinion should) report an error when a non-void function has an
expressionless return. They must report something, but I would support
a move to make it an error rather than a warning. Is there a petition I
can sign?

So are you at odds with everyone else? Well, yes, if you include the
fact that I don't want to spend much time posting to comp.lang.c about
all the things I'd like gcc to do differently.

--
Ben.

Keith Thompson

unread,
Aug 27, 2018, 1:54:27 PM8/27/18
to
David Brown <david...@hesbynett.no> writes:
> On 27/08/18 03:12, Bart wrote:
[...]
> A "return" in a non-void function needs a diagnostic. Your compiler
> gives a diagnostic, gcc gives a diagnostic. It is not the compiler's
> fault that you have trouble with that.

In C99 and C11:
A return statement with an expression shall not appear in a
function whose return type is void. A return statement without
an expression shall only appear in a function whose return type
is void.

In C90:
A return statement with an expression shall not appear in a function
whose return type is void.

A return statement with no expression *was* allowed in on-void
functions. This allowed for pre-ANSI use of implicit int functions
acting as void functions. The restriction was added in C99 along with
dropping the implicit int rule.

So if gcc is invoked with -std=c90 or -std=gnu90 or equivalent (and the
latter was the default until a few releases ago), it will likely not
complain about a `return;` statement in a non-void function.

[...]

>> If I give it:
>>
>> f() {fred(10);}
>>
>> again no errors from gcc, only warnings.
>
> It is legal C. It is not good, modern C, but it is legal. Conforming
> compilers have to accept it.

Not quite. f() is defined with no parameters, but the declaration
doesn't indicate that. The call `fred(10)` does not violate any
constraint or syntax rule, but it does have undefined behavior.
A conforming compiler could reject it on that basis (see 3.4.3p2).
(One could argue that it cannot reject it unless it can prove that the
call will actually be executed.)

[...]

>> But back to the errors:
>>
>> f() {fred(); fred(10,20,30);}
>>
>> Again, just warnings. FFS, there are at least four things wrong with
>> that program! And I'm not talking about initialised unsigned char string
>> from non-signed bytes either.

You should take warnings far more seriously than you do. It is IMHO
unfortunate that the standard does not require any distinction between
warnings that are required diagnostics and warnings that are optional.
But then the standard's requirements for diagnostics are (deliberately)
rather lax.

[...]

Keith Thompson

unread,
Aug 27, 2018, 2:26:41 PM8/27/18
to
Bart <b...@freeuk.com> writes:
> On 27/08/2018 15:22, David Brown wrote:
>>> Apparently C uses void(*)(void) for this purpose, although it appears to
>>> still require a cast to that pointer type.
>>
>> Where did you get the idea that C uses "void(*)(void)" for this purpose?
>
> ME [12-AUG-18 Mixed Arithmetic]:
> >> How would YOU rewrite a table like this of mixed function pointers:
> >>
> >> void *table[] = {malloc, realloc, free, printf, puts};
>
> BEN:
> > typedef void func(void);
> >
> > func *table[] = {
> > (func *)malloc, (func *)realloc, (func *)free, (func *)printf,
> (func *)puts
> > };

That demonstrates only that Ben would do it that way. It's a big leap
from that to "C uses ...".

Using `typedef void func(void)` is one reasonable way to define a
generic function type. It has the drawback that it's a common type for
actual functions, which could suppress warnings for some uses that
should have a cast. I suggested elsewhere in this thread using a unique
type for the function. For example:

typedef struct unused *func(struct unused);
int main(void) {
func *gp = (func*)main;
}

It's very slightly more complicated that Ben's approach. Either is
valid. Neither is suggested by the C standard, which merely says that
different function pointer types can be converted back and forth.

If you want to use void* for that purpose, you can probably persuade
your compiler to let you get away with it. We pedants will likely
point out that converting between void* and a function pointer type
is probably either undefined behavior or a constraint violation.
You will pretend that that true statement constitutes an objection
to you writing your code the way you want to.

>>> I would also have used that, except that (1) a cast is still need; (2)
>>> such a pointer could be also be a valid function pointer type, it is not
>>> a generic type.
>>
>> This is /generated/ C code we are still talking about, not manually
>> written C code?
>
> The cast has to be in the original source.

Why? You translate your language to C. Is your translator incapable of
adding a C cast that does not appear as a cast in your source language?

[...]

> In modern processors there's no reason why you can't cast a void* to
> function pointer or vice versa, as they are almost certain to be the
> same size.

And if you ask your compiler to be sufficiently lax, it will probably
let you do that.

Keith Thompson

unread,
Aug 27, 2018, 2:37:32 PM8/27/18
to
Ben Bacarisse <ben.u...@bsb.me.uk> writes:
> Richard Damon <Ric...@Damon-Family.org> writes:
[...]
> <snip>
>> If you are generating code that depends on machine tricks (even if you
>> think ALL machines you can think of targeting do it that way), then to
>> use C as an intermediary language, you need to put the implementation
>> into a mode that allows those tricks or generate code that doesn't need
>> those tricks but follows the rules of the C Abstract machine. The C
>> language allows for both if you use it right.
>
> If the machine generated code needs to store all pointers in a common
> type, you can do the conversion via (or indeed store the pointers as)
> uintptr_t. That should give you no warnings, which is a plus or a minus
> depending on how you use the generated C code!

There's no guarantee that uintptr_t can hold a converted function
pointer without loss of information. For example, a conforming
implementation could make uintptr_t and all object pointer types 64
bits, and function pointers 128 bits.

jacobnavia

unread,
Aug 27, 2018, 3:51:16 PM8/27/18
to
Le 27/08/2018 à 14:19, James Kuyper a écrit :
> Like all identifiers with external linkage declared in the C standard
> headers, "malloc" is a reserved identifier when used with external
> linkage, regardless of whether or not you #include the relevant header
> (7.1.3p1). If it had been declared with internal linkage, then the
> implementation would be required to pay attention to how it was actually
> declared.

This is just *not true* !!!!!!!


Consider this

static double malloc(double a) { return a/0.75665444;}
int main(void) { malloc(5); }

If I compile it
jacob@rock64:/tmp$ gcc tmalloc.c
tmalloc.c:1:15: warning: conflicting types for built-in function 'malloc'
static double malloc(double a) { return a/0.75665444;}

But in this newsgroup gcc is ALWAYS RIGHT.

I remember the messages of Thompson and Heathfield complaining about my
compiler because of "errors" much less significant than these ones!

But gcc is right of course...

:-)

Ben Bacarisse

unread,
Aug 27, 2018, 4:22:02 PM8/27/18
to
Bart <b...@freeuk.com> writes:

> On 27/08/2018 02:53, Richard Damon wrote:
>> On 8/26/18 8:50 PM, Bart wrote:
>
>>> (1) Conversion between function pointers and void*
>
>> (1) You should know that function pointers and void* data pointers are
>> not compatible, on some machines they are vastly different sizes.
>
> The thing with function pointers and void*, is because I use void* in
> the source language to represent a generic function pointer.

In the long-run I think you'd be better off defining a generic pointer:

typedef union {
void *dp;
void (*fp)(void);
} Pointer;

Another solution is to use uintptr_t as a generic pointer type in the
target C code.

> Apparently C uses void(*)(void) for this purpose, although it appears
> to still require a cast to that pointer type.

C doesn't privilege that type in any way, but lots of people use if
because it's sort of minimal. Others you'll see are void (*)() and int
(*)().

I've also used T *(*)(T *, ...) in a language interpreter, where T was
the universal data type for the language in question, but then all the
functions being stored and manipulated really did have that type. (I
know that in this case you are translating, not interpreting.)

> So in the source language, I would prefer to still use void* for this
> purpose, which also removes the need for casts to convert any function
> address to the generic form.
>
> Given that, the C translator at some point will see a cast like this
> but in intermediate representation:
>
> (void*)malloc # may also be implicit
>
> and needs to decide how to represent that as C.

That could be

(uintptr_t)malloc

or

(Pointer){.fp = malloc}

> Up to know I've left it as that, as it is likely to work perfectly on
> my intended targets (namely x86 and ARM), and C compiler didn't mind
> (mine doesn't).

OK. That seems perfectly reasonable.

> But the pedants here objected very strongly to it.

Why do you care that people "objected very strongly to it"? I don't
recall exactly what this strong objection amounted to, but you can just
carry on doing what works anyway.

--
Ben.

Lew Pitcher

unread,
Aug 27, 2018, 4:28:10 PM8/27/18
to
jacobnavia wrote:

> Le 27/08/2018 à 14:19, James Kuyper a écrit :
>> Like all identifiers with external linkage declared in the C standard
>> headers, "malloc" is a reserved identifier when used with external
>> linkage, regardless of whether or not you #include the relevant header
>> (7.1.3p1). If it had been declared with internal linkage, then the
>> implementation would be required to pay attention to how it was actually
>> declared.
>
> This is just *not true* !!!!!!!
>
>
> Consider this
>
> static double malloc(double a) { return a/0.75665444;}
> int main(void) { malloc(5); }
>
> If I compile it
> jacob@rock64:/tmp$ gcc tmalloc.c
> tmalloc.c:1:15: warning: conflicting types for built-in function 'malloc'
> static double malloc(double a) { return a/0.75665444;}

Are you referring to the warning?

> But in this newsgroup gcc is ALWAYS RIGHT.

First off, /you/ are the one who dragged gcc into /this/ specific
discussion.

Secondly, as you are well aware, gcc does /not/, without specific options,
compile the Standard version of the C language. If you want GCC to compile
to the relevant ISO C standard, you have to include a number of commandline
options that you have (conveniently) neglected.

Try again with
gcc -Wall -fno-builtin -std=c99 -pedantic-errors
substituting, of course, the relevent standard for "c99"

[snip]

--
Lew Pitcher
"In Skills, We Trust"
PGP public key available upon request

Keith Thompson

unread,
Aug 27, 2018, 4:30:03 PM8/27/18
to
jacobnavia <ja...@jacob.remcomp.fr> writes:
> Le 27/08/2018 à 14:19, James Kuyper a écrit :
>> Like all identifiers with external linkage declared in the C standard
>> headers, "malloc" is a reserved identifier when used with external
>> linkage, regardless of whether or not you #include the relevant header
>> (7.1.3p1). If it had been declared with internal linkage, then the
>> implementation would be required to pay attention to how it was actually
>> declared.
>
> This is just *not true* !!!!!!!

In fact it is.

> Consider this
>
> static double malloc(double a) { return a/0.75665444;}
> int main(void) { malloc(5); }
>
> If I compile it
> jacob@rock64:/tmp$ gcc tmalloc.c
> tmalloc.c:1:15: warning: conflicting types for built-in function 'malloc'
> static double malloc(double a) { return a/0.75665444;}

Yes, that's a perfectly reasonable warning. Using the name "malloc" to
refer to something other than the standard function is likely, but not
not certain, to be a bad idea.

It's not a required diagnostic, and in fact both "gcc -std=c11 -pedantic"
and "gcc -std=c11 -pedantic-errors" issue a non-fatal warning.

Your program is valid, and in fact I believe it's strictly
conforming. gcc accepts it after emitting a non-fatal warning,
which is conforming behavior. (The difficulty of distinguishing
between required diagnostics and compiler-specific optional warnings
is IMHO unfortunate.)

Even without the "static", "gcc -std=c11 -pedantic-errors" issues
a non-fatal warning, not the fatal error it usually uses for
language-required diagnostics.. Defining or declaring a reserved
identifier causes a program's behavior to be undefined; it does
not require a diagnostic. (One possible result of the undefined
behavior is that the program might call the standard malloc() rather
than the user-defined malloc(). Another is that the program may
behave just as if a name other than "malloc" had been used.)

> But in this newsgroup gcc is ALWAYS RIGHT.

I don't recall anyone making that claim. I certainly haven't.

> I remember the messages of Thompson and Heathfield complaining about my
> compiler because of "errors" much less significant than these ones!

And you still haven't gotten over it. I don't understand why you treat
bug reports as personal attacks.

> But gcc is right of course...

In this case, yes, gcc happens to be right.

I expect you will either ignore this response or take it as a personal
attack. It isn't. I'm merely pointing out that you are mistaken on
this particular point.

David Brown

unread,
Aug 27, 2018, 4:31:17 PM8/27/18
to
On 27/08/18 17:45, Bart wrote:
> On 27/08/2018 15:22, David Brown wrote:
>
>>> Apparently C uses void(*)(void) for this purpose, although it appears to
>>> still require a cast to that pointer type.
>>
>> Where did you get the idea that C uses "void(*)(void)" for this purpose?
>
>
> ME [12-AUG-18 Mixed Arithmetic]:
> >> How would YOU rewrite a table like this of mixed function pointers:
> >>
> >>   void *table[] = {malloc, realloc, free, printf, puts};
>
> BEN:
> >    typedef void func(void);
> >
> >    func *table[] = {
> >      (func *)malloc, (func *)realloc, (func *)free, (func *)printf,
> (func *)puts
> >    };
>

You asked Ben how /he/ would write it. If you had asked me, I'd
probably have said much the same. (Keith's alternative is a little more
advanced, and a little safer.) That is because I know it works on gcc
(it's documented in the manual), and I am confident it would work on
non-gcc compilers that I sometimes use. But I also know it is not
guaranteed by the C standards - there is no common function pointer type
in standard C. "void (*)(void)" is a type that will work well for most
compilers for targets where all function pointers have the same size.
Few, if any, compilers/processors have different sized function pointers
except for "near/far" style extensions. Most of the details here are
implementation-dependent.

So again you are leaping from one example to "C does it this way".

>
>>>
>>> I would also have used that, except that (1) a cast is still need; (2)
>>> such a pointer could be also be a valid function pointer type, it is not
>>> a generic type.
>>
>> This is /generated/ C code we are still talking about, not manually
>> written C code?
>
> The cast has to be in the original source.

There does not need to be a correlation like this between source
language and the generated C code. This is a completely artificial
constraint that you have put in.

>
>   If that's the case, my answers are (1) So what? and (2)
>> So what?
>
> It's like using char* to do the job of void*.

"char*" can sometimes do a similar job to "void*". "void*" cannot do
the job of "void (*)(void)". I don't see the similarity.

>
> I'm surprised you don't get that.
>
>> It's your language, you can call your types whatever you want there.
>> But you can't call them something and expect that this somehow makes
>> them the same as a C type of the same name.
>
> In modern processors there's no reason why you can't cast a void* to
> function pointer or vice versa, as they are almost certain to be the
> same size.

As I said, that is simply not true.

There are lots of processors with different sized pointers for function
and data pointers - new, current processors used in microcontrollers, as
well as a variety with different "memory model" support. You probably
remember that from your DOS days - this sort of thing is not gone from
programming. (Unlike hacks such as near/far pointers, banking, etc.,
there is no problem or inconvenience about having different sized
pointers for functions and data - unless you make unnecessary and
potentially incorrect assumptions.)

>
> Bizarrely, C allows casting between function pointers and ints, but not
> between function pointers and ordinary pointers!

Yes - if the implementation allows it, and the integer type is big
enough. You can't do much with the converted result (unless the
implementation gives you more features).

>
> Unless the ordinary pointer has the value 0, then casting between a
> function pointer and (void)*0 IS allowed.
>
> Who makes up this stuff?

Some of it certainly seems a little weird, or a missed opportunity.

>
> (BTW I think I've just found a way around the problem: you can cast from
> from pointer to function pointer VIA an int cast. Although it will need
> to be an int matching the size of the pointers of either side. (If the
> two pointer types are a different size, then there's a genuine problem.)
>
> So, apparently, it can be done. In which case why the need to go to such
> lengths?)

C lets you do a lot of things without the behaviour being defined in the
standards. If the compiler says its allowed, then that's fine - but it
is not defined behaviour standard C. Maybe it is portable enough for
your needs.

Using the suggested "void (*)(void)" type would be better, however -
even if that may also need casts.

>
>> The way to stop people telling you you are doing daft things in your C
>> code is to listen to others and stop doing daft things - not to stop
>> writing C code.
>
> This group is more like a secret society than anything else. with lots
> of arcane, made-up rules, initiation procedures and a hierarchy of
> members. Plus all their complicated tools with their 1001 settings.
> [More than that actually. Anyone outside that clique, have a read of
> Asimov's story /Profession/ to get a better idea of what I'm talking
> about.]
>

It's a strange sort of secret society that goes to such an effort to
tell you how it all works, explain all the rules, give reasons for some
of the rules (when we can figure them out ourselves), and tell you again
and again how to use these complicated tools.

> People just want to run their low level programs on their machine of
> choice; why do they have to do battle with the C language, C compilers,
> C options and the clc cartel?
>

People /do/ write and run low-level programs in C all the time (as well
as high-level programs and everything in between). People are
successful with C when they decide to work /with/ the language and the
tools, instead of /against/ them.

> This is why there need to be modern alternatives - not the even more
> bloated ones - that don't consist of 90% ancient baggage.
>

The success of C has shown that there simply is not such a need.

There is a need for safer and more powerful languages for low-level
programming - but I don't think you'd like them either. They are even
less "transparent" than C, and have more features.

Ben Bacarisse

unread,
Aug 27, 2018, 4:33:32 PM8/27/18
to
Keith Thompson <ks...@mib.org> writes:

> Ben Bacarisse <ben.u...@bsb.me.uk> writes:
>> Richard Damon <Ric...@Damon-Family.org> writes:
> [...]
>> <snip>
>>> If you are generating code that depends on machine tricks (even if you
>>> think ALL machines you can think of targeting do it that way), then to
>>> use C as an intermediary language, you need to put the implementation
>>> into a mode that allows those tricks or generate code that doesn't need
>>> those tricks but follows the rules of the C Abstract machine. The C
>>> language allows for both if you use it right.
>>
>> If the machine generated code needs to store all pointers in a common
>> type, you can do the conversion via (or indeed store the pointers as)
>> uintptr_t. That should give you no warnings, which is a plus or a minus
>> depending on how you use the generated C code!
>
> There's no guarantee that uintptr_t can hold a converted function
> pointer without loss of information. For example, a conforming
> implementation could make uintptr_t and all object pointer types 64
> bits, and function pointers 128 bits.

Sure. I was offering a practical solution in the case where the
pointers were the same size and representation (because the source
language has a common pointer type). It still may not work as it's not
guaranteed on any implementation, so I should probably have pointed that
out.

--
Ben.

David Brown

unread,
Aug 27, 2018, 4:38:41 PM8/27/18
to
The "gcc-specific" aspect of the "void (*)(void)" type is that it if you
have "-Wcast-function-type" in action (it is part of "-Wextra") you get
warnings about casts between incompatible pointer types - unless one of
the types is "void (*)(void)". So it is not a matter of gcc handling
that type differently from the standard, but of it using it as a
"generic function pointer" type for warnings. (It might have been
helpful if I'd mentioned this in my previous post...)

>
> In effect any function pointer type can be used as a generic function
> pointer type (though there's no implicit conversion as there is with
> void*). If you want to define a specific type to be used as a generic
> function pointer type, you might consider a type that's never used
> otherwise, so that you'll always get a warning if you try to use it
> without a cast. For example:
>
> typedef struct undefined *generic_function(struct undefined*);
>
> An implementation could have different sizes for different function
> pointer types, but the conversion requirement would make that awkward.
>

Yes, I was wondering about that.

David Brown

unread,
Aug 27, 2018, 4:44:50 PM8/27/18
to
On 27/08/18 21:51, jacobnavia wrote:
> Le 27/08/2018 à 14:19, James Kuyper a écrit :
>> Like all identifiers with external linkage declared in the C standard
>> headers, "malloc" is a reserved identifier when used with external
>> linkage, regardless of whether or not you #include the relevant header
>> (7.1.3p1). If it had been declared with internal linkage, then the
>> implementation would be required to pay attention to how it was actually
>> declared.
>
> This is just *not true* !!!!!!!
>

What James wrote /is/ true - it is a quotation from the standards.

But it is entirely possible that gcc is getting something wrong here.
From your example below, it looks like that is the case.

>
> Consider this
>
> static double malloc(double a) { return a/0.75665444;}
> int main(void) { malloc(5); }
>
> If I compile it
> jacob@rock64:/tmp$ gcc tmalloc.c
> tmalloc.c:1:15: warning: conflicting types for built-in function 'malloc'
>  static double malloc(double a) { return a/0.75665444;}
>

As far as I understand things here, which may be incorrect, that's a bug
in gcc.

> But in this newsgroup gcc is ALWAYS RIGHT.

No, I don't believe there are many here who think that. There are a few
who seem to view "gcc does this" as more important than reading the
standards, but not many.

>
> I remember the messages of Thompson and Heathfield complaining about my
> compiler because of "errors" much less significant than these ones!
>

I can't see this being a significant error. How often do people write
code with a static "malloc" function? If you and I are correct that
this is a gcc bug, it has probably been there for a very long time -
hardly a significant bug!

David Brown

unread,
Aug 27, 2018, 4:48:13 PM8/27/18
to
On 27/08/18 19:54, Keith Thompson wrote:
> David Brown <david...@hesbynett.no> writes:
>> On 27/08/18 03:12, Bart wrote:
> [...]
>> A "return" in a non-void function needs a diagnostic. Your compiler
>> gives a diagnostic, gcc gives a diagnostic. It is not the compiler's
>> fault that you have trouble with that.
>
> In C99 and C11:
> A return statement with an expression shall not appear in a
> function whose return type is void. A return statement without
> an expression shall only appear in a function whose return type
> is void.
>
> In C90:
> A return statement with an expression shall not appear in a function
> whose return type is void.
>
> A return statement with no expression *was* allowed in on-void
> functions. This allowed for pre-ANSI use of implicit int functions
> acting as void functions. The restriction was added in C99 along with
> dropping the implicit int rule.
>
> So if gcc is invoked with -std=c90 or -std=gnu90 or equivalent (and the
> latter was the default until a few releases ago), it will likely not
> complain about a `return;` statement in a non-void function.

I hadn't checked in C90. (My pdf copy of the standard there has no
clickable table of contents - it's much more tedious to navigate.)

>
> [...]
>
>>> If I give it:
>>>
>>> f() {fred(10);}
>>>
>>> again no errors from gcc, only warnings.
>>
>> It is legal C. It is not good, modern C, but it is legal. Conforming
>> compilers have to accept it.
>
> Not quite. f() is defined with no parameters, but the declaration
> doesn't indicate that. The call `fred(10)` does not violate any
> constraint or syntax rule, but it does have undefined behavior.
> A conforming compiler could reject it on that basis (see 3.4.3p2).
> (One could argue that it cannot reject it unless it can prove that the
> call will actually be executed.)
>

Fair enough.

Keith Thompson

unread,
Aug 27, 2018, 4:59:26 PM8/27/18
to
There's nothing gcc-specific about this. N1570 6.3.2.3p8:

A pointer to a function of one type may be converted to a pointer to
a function of another type and back again; the result shall compare
equal to the original pointer. If a converted pointer is used to
call a function whose type is not compatible with the referenced
type, the behavior is undefined.

This likely implies that all function pointers are going to be the same
size (even if they're not the same size as object pointers). An
implementation could give different function pointer types different
sizes, but it would still have to make round-trip conversions work
correctly.

[...]

>> Bizarrely, C allows casting between function pointers and ints, but not
>> between function pointers and ordinary pointers!
>
> Yes - if the implementation allows it, and the integer type is big
> enough. You can't do much with the converted result (unless the
> implementation gives you more features).

Casting between function pointers and integers is not a constraint
violation, regardless of whether the target is big enough.

[...]

Keith Thompson

unread,
Aug 27, 2018, 5:10:07 PM8/27/18
to
Keith Thompson <ks...@mib.org> writes:
[...]
> There's nothing gcc-specific about this. N1570 6.3.2.3p8:
[...]

That followup was largely a repetition of an earlier one. I should pay
more attention to what's already been said.

Keith Thompson

unread,
Aug 27, 2018, 5:15:26 PM8/27/18
to
David Brown <david...@hesbynett.no> writes:
> On 27/08/18 21:51, jacobnavia wrote:
[...]
>> static double malloc(double a) { return a/0.75665444;}
>> int main(void) { malloc(5); }
>>
>> If I compile it
>> jacob@rock64:/tmp$ gcc tmalloc.c
>> tmalloc.c:1:15: warning: conflicting types for built-in function 'malloc'
>>  static double malloc(double a) { return a/0.75665444;}
>
> As far as I understand things here, which may be incorrect, that's a bug
> in gcc.

I don't believe so. Compilers can warn about anything they like. This
is not a language-required diagnostic.

[...]

james...@alumni.caltech.edu

unread,
Aug 27, 2018, 6:31:01 PM8/27/18
to
On Monday, August 27, 2018 at 7:40:53 AM UTC-4, Bart wrote:
> On 27/08/2018 03:09, james...@alumni.caltech.edu wrote:
> > On Sunday, August 26, 2018 at 8:50:54 PM UTC-4, Bart wrote:
>
>
> >> The exact same original sources translate to x64 native code with none
> >> of the problems I get from doing it in C.
> >
> > Then I strongly recommend going with x64 native code and abandoning a language you're tempermentally incapable of learning to use correctly.
> >
>
> I've already abandoned it. Actually I think I only spent one year
> writing it around 2012, and even then I had to use it via a syntax
> wrapper to make it less painful.

When I recommended abandoning C, I was referring to all of the following, too:

> Now I'm only using it as an intermediate language and there the problems
> are showing up. (Some compilers don't like '$' in names. Some don't like
> long string constants. Some need __attribute__(dllimport). etc etc. Plus
> all this UB business.)
>
> But I still have to use interfaces specified in C. And I'm still
> maintaining my own C compiler but as a private project. One which is my
> first choice to compile short programs as it will tell me what's what
> without any arm-twisting.
>
> Note that maintaining a C compiler is not the same thing as writing C
> code; the compiler isn't written in C.

It doesn't matter whether you write the C code or your program writes the C code - being tempermentally incapable of learning how C actually works makes it a very poor choice for that purpose.

james...@alumni.caltech.edu

unread,
Aug 27, 2018, 7:01:44 PM8/27/18
to
On Monday, August 27, 2018 at 3:51:16 PM UTC-4, jacobnavia wrote:
> Le 27/08/2018 à 14:19, James Kuyper a écrit :
> > Like all identifiers with external linkage declared in the C standard
> > headers, "malloc" is a reserved identifier when used with external
> > linkage, regardless of whether or not you #include the relevant header
> > (7.1.3p1). If it had been declared with internal linkage, then the
> > implementation would be required to pay attention to how it was actually
> > declared.
>
> This is just *not true* !!!!!!!

It isn't? Why? None of what you say below is relevant, because it's
about what one particular implementation does. If what it does was
inconsistent with what I said above, that would merely indicate that the
compiler was non-conforming. Only a citation from the standard is
relevant to the question of whether or not my statement was correct.

> Consider this
>
> static double malloc(double a) { return a/0.75665444;}
> int main(void) { malloc(5); }
>
> If I compile it
> jacob@rock64:/tmp$ gcc tmalloc.c

You're using gcc in a mode that, very explicitly, make no claim to
conform to any version of the C standard. How is that relevant to my
comment about what the C standard requires of fully conforming
implementations?

> tmalloc.c:1:15: warning: conflicting types for built-in function 'malloc'
> static double malloc(double a) { return a/0.75665444;}

a) The standard never prohibits generation of diagnostic messages
b) The standard never imposes any requirements on the validity of the
message text. This text would be unambiguously incorrect as far as the C
standard is concerned, but that would not, in itself, constitute a
conformance problem, even if gcc did make conformance promises that
applied in this mode. Since this is actually being compiled as GnuC
code, rather than as C code, it's entirely possible that the error
message is telling the exact, literal truth about how this code is
interpreted according to GnuC.

> But in this newsgroup gcc is ALWAYS RIGHT.

No one has ever said or implied that.

> I remember the messages of Thompson and Heathfield complaining about my
> compiler because of "errors" much less significant than these ones!

The key difference was that, while the standard NEVER prohibits the
generation of diagnostics, it does sometimes mandate them - and your
compiler failed to generate some mandatory diagnostics.

Bart

unread,
Aug 27, 2018, 7:39:37 PM8/27/18
to
On 27/08/2018 23:30, james...@alumni.caltech.edu wrote:
> On Monday, August 27, 2018 at 7:40:53 AM UTC-4, Bart wrote:

>> I've already abandoned it. Actually I think I only spent one year
>> writing it around 2012, and even then I had to use it via a syntax
>> wrapper to make it less painful.
>
> When I recommended abandoning C, I was referring to all of the following, too:

I wasn't planning on posting again in this group but I'm not going to
let that go.

I think you have a hell of cheek telling me not to use C (and putting me
in the same category as poor Bill Cunningham to boot).

Maybe I don't know it as well as you, but so what? Probably 99% of C
users won't know it as well as you either, with your detailed knowledge
of the C standards; maybe they should all give up on it too? Mind you
those 99% would find standards minutia too mind-numbingly dull to want
to learn it.

Programming languages should be usable by a range of abilities, not just
an elite. Although I would hardly call C itself an elitist language,
despite the attempts to make it that. It's just another crappy low level
language that got lucky.

I can't anyway give up all uses because it is used for the APIs I need
to write programs in other languages.

If I don't write it myself, it's because I find my own language superior
to it, and the compiler more down to earth (no nonsense about
conformance or constraint violation; when something is wrong, it's
wrong). (Here's about 120 reasons why I prefer it:
https://github.com/sal55/mlang/blob/master/mlang/list.md.)

> It doesn't matter whether you write the C code or your program writes the C code - being tempermentally incapable of learning how C actually works makes it a very poor choice for that purpose.

Temperamental is right. I haven't got the patience for dealing with a
crude hack of a language and compilers that have to be told what is and
isn't an error.

If I choose not to write it in, it will because it doesn't meet my
standards. But it will be my choice; not yours.

Do I tell YOU what language you should or should not be using?

As I said, you have a bloody cheek.

Richard Damon

unread,
Aug 27, 2018, 10:33:20 PM8/27/18
to
On 8/27/18 11:45 AM, Bart wrote:
> In modern processors there's no reason why you can't cast a void* to
> function pointer or vice versa, as they are almost certain to be the
> same size.

Try that on a PIC24. They aren't.

Ian Collins

unread,
Aug 28, 2018, 12:44:50 AM8/28/18
to
On 28/08/18 11:39, Bart wrote:
> On 27/08/2018 23:30, james...@alumni.caltech.edu wrote:
>> On Monday, August 27, 2018 at 7:40:53 AM UTC-4, Bart wrote:
>
>>> I've already abandoned it. Actually I think I only spent one year
>>> writing it around 2012, and even then I had to use it via a syntax
>>> wrapper to make it less painful.
>>
>> When I recommended abandoning C, I was referring to all of the following, too:
>
> I wasn't planning on posting again in this group but I'm not going to
> let that go.
>
> I think you have a hell of cheek telling me not to use C (and putting me
> in the same category as poor Bill Cunningham to boot).
>
> Maybe I don't know it as well as you, but so what? Probably 99% of C
> users won't know it as well as you either...

But most of that 99% would be willing to learn...

--
Ian.

james...@alumni.caltech.edu

unread,
Aug 28, 2018, 12:49:48 AM8/28/18
to
On Monday, August 27, 2018 at 7:39:37 PM UTC-4, Bart wrote:
> On 27/08/2018 23:30, james...@alumni.caltech.edu wrote:
> > On Monday, August 27, 2018 at 7:40:53 AM UTC-4, Bart wrote:
>
> >> I've already abandoned it. Actually I think I only spent one year
> >> writing it around 2012, and even then I had to use it via a syntax
> >> wrapper to make it less painful.
> >
> > When I recommended abandoning C, I was referring to all of the following, too:
>
> I wasn't planning on posting again in this group but I'm not going to
> let that go.
>
> I think you have a hell of cheek telling me not to use C (and putting me
> in the same category as poor Bill Cunningham to boot).

I'm advising you against using C, not telling you. I have no authority
to tell you to do anything, and I didn't use wording that implies that
I do. That advice is based upon how much aggravation that choice has
been giving you. If you like being aggravated, please continue following
your current path - it's a very efficient way of achieving that goal
(please note that this is also advice, not an order).

However, I personally don't like being aggravated, so please go ahead
with your plan to stop posting to this group. In case it's unclear, that
is a request, which you're free to ignore. It's not an order.

> Maybe I don't know it as well as you, but so what? Probably 99% of C
> users won't know it as well as you either, with your detailed knowledge
> of the C standards; maybe they should all give up on it too?

Why should they? You seem to be unique among the C programmers I've
known, in the degree that you are aggravated by the language you choose
to use. Most programmers either don't get that aggravated, or if they
do, they stop using the language, so the people who are still using the
language are, by and large, not seriously aggravated by the issues that
bother you so much.

David Brown

unread,
Aug 28, 2018, 3:26:05 AM8/28/18
to
On 27/08/18 23:09, Keith Thompson wrote:
> Keith Thompson <ks...@mib.org> writes:
> [...]
>> There's nothing gcc-specific about this. N1570 6.3.2.3p8:
> [...]
>
> That followup was largely a repetition of an earlier one. I should pay
> more attention to what's already been said.
>

I had a feeling it sounded familiar. There's nothing wrong with
repetition for emphasis - and proof by repeated assertion is the
backbone of Usenet :-)

(In case the smiley is missed, your point was valid and I replied to it
in the other branch of the thread.)

David Brown

unread,
Aug 28, 2018, 3:41:19 AM8/28/18
to
On 27/08/18 23:15, Keith Thompson wrote:
> David Brown <david...@hesbynett.no> writes:
>> On 27/08/18 21:51, jacobnavia wrote:
> [...]
>>> static double malloc(double a) { return a/0.75665444;}
>>> int main(void) { malloc(5); }
>>>
>>> If I compile it
>>> jacob@rock64:/tmp$ gcc tmalloc.c
>>> tmalloc.c:1:15: warning: conflicting types for built-in function 'malloc'
>>> static double malloc(double a) { return a/0.75665444;}
>>
>> As far as I understand things here, which may be incorrect, that's a bug
>> in gcc.
>
> I don't believe so. Compilers can warn about anything they like. This
> is not a language-required diagnostic.
>

After reading this, and some other posts here, I think you are right
that gcc certainly /may/ warn about this. But I think it is wrong to do
so. (Whether that is a bug, or just a design decision with which I
disagree, is another matter.)

The issue here apparently stems from the "-fbuiltin" feature of gcc.
This gives gcc more detailed knowledge of a range of common library
functions and allows significant optimisations for many calls to memcpy,
strlen, and the like. The trouble here is that "-fbuiltin" is enabled
by default and forces the standard function type on these functions.
Normally, "-fbuiltin" is exactly what you want, so it makes sense to
have it by default - but the warning about the legal code here is, I
think, inappropriate with "-std=cNN -pedantic".


Bart

unread,
Aug 28, 2018, 7:09:53 AM8/28/18
to
I missed out "general purpose".

However, I've now discovered that C doesn't object to casting between
function pointers and adequately sized integers. So this apparently this
can be done, even on PIC24.

Then it's purely a language quirk in not allowing direct casting between
function pointers and non-pointers, specifically void* as that can be
designed to be of a size to accommodate any kind of pointer.



[Apologies for piggy-backing as I'm trying to minimise posts:]

On 28/08/2018 05:49, james...@alumni.caltech.edu wrote:
> Why should they? You seem to be unique among the C programmers I've
> known, in the degree that you are aggravated by the language you choose
> to use.

Most of the aggravation is caused by people here vehemently disagreeing
with me. On just about everything.

If it was just me and the language and a user-friendly compiler (like
the one I made) it wouldn't be so bad. But introduce all these contrary
attitudes, the Unix-culture that comes with it, plus all those decidedly
unfriendly tools, and it's a different story.


--
bart


James Kuyper

unread,
Aug 28, 2018, 7:32:26 AM8/28/18
to
I hadn't bothered checking before, since he specified "gcc tmalloc.c". I
am disappointed to find that it produces the same error message with
-std=c11 -pedantic. With those options, I think it would still be
entirely appropriate to warn about the fact that this definition with
internal linkage shadows the one from the C standard library. Since it
is a reserved identifier for use with external linkage, it is still
arguably reasonable to provide that warning despite the fact that
<stdlib.h> has not been #included (it provides a different and correct
warning if it is #included). But the explanation for this warning is
just plain wrong for standard C. It doesn't render the implementation
non-conforming, but it's still wrong.

mark.b...@gmail.com

unread,
Aug 28, 2018, 7:59:54 AM8/28/18
to
On Tuesday, 28 August 2018 12:09:53 UTC+1, Bart wrote:

> Most of the aggravation is caused by people here vehemently disagreeing
> with me. On just about everything.

https://en.wikipedia.org/wiki/They_Were_All_Out_of_Step_But_Jim#/media/File:They_Were_All_Out_of_Step_But_Jim_sheet_music_cover_art.jpg

Richard Damon

unread,
Aug 28, 2018, 8:09:44 AM8/28/18
to
On 8/28/18 7:09 AM, Bart wrote:
> On 28/08/2018 03:33, Richard Damon wrote:
>> On 8/27/18 11:45 AM, Bart wrote:
>>> In modern processors there's no reason why you can't cast a void* to
>>> function pointer or vice versa, as they are almost certain to be the
>>> same size.
>>
>> Try that on a PIC24. They aren't.
>
> I missed out "general purpose".
>
> However, I've now discovered that C doesn't object to casting between
> function pointers and adequately sized integers. So this apparently this
> can be done, even on PIC24.
>
> Then it's purely a language quirk in not allowing direct casting between
> function pointers and non-pointers, specifically void* as that can be
> designed to be of a size to accommodate any kind of pointer.
>

I suppose it depends on your definition of 'general purpose'. While you
wouldn't make a 'desktop' out of a PIC, they can be used for machines
that are flexible purposed, i.e. not dedicated to a single specific task
like a thermostat.

But also, C isn't limited to being a 'desktop' language, and I would say
one important use is in the embedded world, and the standard even
acknowledges that and defines two types of system, 'Free Standing' and
'Hosted', which differ in how much of the library they need to support
(no need to force support for a file system on a machine without one).

Also, void* is specifically described as being a generic OBJECT pointer,
a pointer that can point to any type of OBJECT, and functions are not
objects.

This goes back to the fact that C isn't the language YOU want it to be.
Which is fine (complaining about it isn't really). One of the strengths
of C is that it has a core language that supports a large number of
implementations that can focus on specific sorts of applications. As a
programmer, you get to choose if you want to write code that is broadly
usable, by restricting yourself to 'standard' features, or you can
choose a suitable implementation and write code that makes and uses a
lot of assumptions about the hardware. The key here is choosing the
right implementation, which in many cases means using the right options
on the compiler you are using.

You seem to want every implementation to work your way without having to
think about it. To make the assumption you want about machines. Yes,
there could be such a language, but it isn't C, and it wouldn't be
nearly as useful.

Most compilers work they way they do because their authors have found
that working that way is what makes the most of their users happy (or at
least they think it does). The fact that your requirements are not the
norm isn't the fault of the language.

David Brown

unread,
Aug 28, 2018, 8:20:57 AM8/28/18
to
On 28/08/18 13:09, Bart wrote:
> On 28/08/2018 03:33, Richard Damon wrote:
>> On 8/27/18 11:45 AM, Bart wrote:
>>> In modern processors there's no reason why you can't cast a void* to
>>> function pointer or vice versa, as they are almost certain to be the
>>> same size.
>>
>> Try that on a PIC24. They aren't.
>
> I missed out "general purpose".
>
> However, I've now discovered that C doesn't object to casting between
> function pointers and adequately sized integers. So this apparently this
> can be done, even on PIC24.
>

Yes, it can be done. The standard allows it if the implementation has a
big enough integer type. I've worked with microcontrollers where
function pointers are bigger than data pointers, but none where the
function pointers are bigger than the biggest integer type (which would
have to be at least 32 bit).

The are some processors where pointers are rather big and complicated
structures tracking valid ranges, permission bits, and other data as
well as a memory address. I have no experience of such devices, but no
doubt there are C compilers for them.

> Then it's purely a language quirk in not allowing direct casting between
> function pointers and non-pointers, specifically void* as that can be
> designed to be of a size to accommodate any kind of pointer.
>

Absolutely not. If you've got an 8-bit AVR, 16-bit data pointers are
inefficient enough without expanding them to the 24 bits needed to cover
the code address space just so that you can have a single global "void*"
type. (gcc for the AVR does support "far" pointer types for when you
need them - but that is primarily for accessing constant data in the
flash. You don't use them for normal void* or data pointer usage.)

It is rare in coding that you need some sort of generic function pointer
type - rarer still that you need a generic pointer that covers data and
code. You don't punish the very common use of void* and other data
pointers for such rarely needed features.

>
> [Apologies for piggy-backing as I'm trying to minimise posts:]
>
> On 28/08/2018 05:49, james...@alumni.caltech.edu wrote:
>> Why should they? You seem to be unique among the C programmers I've
>> known, in the degree that you are aggravated by the language you choose
>> to use.
>
> Most of the aggravation is caused by people here vehemently disagreeing
> with me. On just about everything.

It's a knack you have. Don't you think it's odd that in such
disagreements, you are almost always on the opposite side from everyone
else in the discussion? I see two explanations for that. Either the
whole group is part of a conspiracy to aggravate and annoy you, or you
are regularly wrong about a number of fundamental points in C. If it is
the first reason, then you would be right to leave the group (that is
/not/ something I would like to see) - if it is the second reason, then
once you understand the root of your problems and open yourself to
learning from others, I am sure progress will be swift.

But don't forget that this is Usenet - it is a place for discussions and
disagreements. Some threads are going to be purely exchanges of ideas,
but most threads of any substance are going to come from differences of
opinion.

mark.b...@gmail.com

unread,
Aug 28, 2018, 8:30:30 AM8/28/18
to
On Tuesday, 28 August 2018 13:20:57 UTC+1, David Brown wrote (to Bart):
> Don't you think it's odd that in such
> disagreements, you are almost always on the opposite side from everyone
> else in the discussion? I see two explanations for that. Either the
> whole group is part of a conspiracy to aggravate and annoy you, or you
> are regularly wrong about a number of fundamental points in C. If it is
> the first reason, then you would be right to leave the group (that is
> /not/ something I would like to see) - if it is the second reason, then
> once you understand the root of your problems and open yourself to
> learning from others, I am sure progress will be swift.

Come on David - you get the memos. It's the first reason - we have a
mailing list specifically to coordinate our efforts to aggravate and annoy
Bart. We even use time travel (which we don't acknowledge having access to)
so that we can retrospectively influence the standards procedures to
maximally inconvenience him.

David Brown

unread,
Aug 28, 2018, 8:59:44 AM8/28/18
to
On 28/08/18 14:09, Richard Damon wrote:
> On 8/28/18 7:09 AM, Bart wrote:
>> On 28/08/2018 03:33, Richard Damon wrote:
>>> On 8/27/18 11:45 AM, Bart wrote:
>>>> In modern processors there's no reason why you can't cast a void* to
>>>> function pointer or vice versa, as they are almost certain to be the
>>>> same size.
>>>
>>> Try that on a PIC24. They aren't.
>>
>> I missed out "general purpose".
>>
>> However, I've now discovered that C doesn't object to casting between
>> function pointers and adequately sized integers. So this apparently this
>> can be done, even on PIC24.
>>
>> Then it's purely a language quirk in not allowing direct casting between
>> function pointers and non-pointers, specifically void* as that can be
>> designed to be of a size to accommodate any kind of pointer.
>>
>
> I suppose it depends on your definition of 'general purpose'. While you
> wouldn't make a 'desktop' out of a PIC, they can be used for machines
> that are flexible purposed, i.e. not dedicated to a single specific task
> like a thermostat.
>
> But also, C isn't limited to being a 'desktop' language, and I would say
> one important use is in the embedded world, and the standard even
> acknowledges that and defines two types of system, 'Free Standing' and
> 'Hosted', which differ in how much of the library they need to support
> (no need to force support for a file system on a machine without one).
>

I would go a little further and say that embedded use is probably the
main area where C is a sensible choice for new projects. C clearly has
major usage in the continuation of existing projects. And it certainly
/is/ used for new projects in a wide range of cases. But for a good
many of these, you could argue that other languages (C++, Go, Rust,
Python, etc.) would often be better choices. For small embedded
systems, the choice is often limited to C or C++ (with occasional
Assembly, Forth, and Ada) - with C often coming out top choice for good,
technical reasons.

> Also, void* is specifically described as being a generic OBJECT pointer,
> a pointer that can point to any type of OBJECT, and functions are not
> objects.

Yes.

David Brown

unread,
Aug 28, 2018, 9:01:49 AM8/28/18
to
What's the point of a secret conspiracy if you tell everyone about it?

Next you'll be revealing that the reason for using legible English in
this group is to make Fir feel uncomfortable.

Anton Shepelev

unread,
Aug 28, 2018, 9:02:44 AM8/28/18
to
David Brown:

>C clearly has major usage in the continuation of existing
>projects. And it certainly /is/ used for new projects in a
>wide range of cases. But for a good many of these, you
>could argue that other languages (C++, Go, Rust, Python,
>etc.) would often be better choices.

Aren't all those languates larger and more complicated than
C? Isn't C's minimalism an artument for new projects?

--
() ascii ribbon campaign - against html e-mail
/\ http://preview.tinyurl.com/qcy6mjc [archived]
It is loading more messages.
0 new messages