Path: csiph.com!eternal-september.org!feeder.eternal-september.org!reader01.eternal-september.org!.POSTED!not-for-mail
From: Tim Rentsch
Newsgroups: comp.lang.c
Subject: Re: Abstract Syntax Tree for C programs
Date: Tue, 04 Jun 2019 10:41:17 -0700
Organization: A noiseless patient Spider
Lines: 102
Message-ID: <86h895fdtu.fsf@mailhub.linuxsc.com>
References: <475067fe-369c-4246-84a1-05b1a3a0c6be@googlegroups.com> <5dd4672f-a571-40bc-bb1a-c14f6c631eb7@googlegroups.com> <87ftop38c1.fsf@bsb.me.uk> <87woi11jh1.fsf@bsb.me.uk>
Mime-Version: 1.0
Content-Type: text/plain; charset=us-ascii
Injection-Info: reader02.eternal-september.org; posting-host="822064cc3cc2a6ececc8a34836f7fa7b"; logging-data="11032"; mail-complaints-to="abuse@eternal-september.org"; posting-account="U2FsdGVkX19XDRxrf+HB3CfpwH/WINHT2kUVEmkGe6g="
User-Agent: Gnus/5.11 (Gnus v5.11) Emacs/22.4 (gnu/linux)
Cancel-Lock: sha1:zaoAmt15QiLBsEZD33GOc1i/6LY= sha1:A+xGRqpffGIknVi2NeNv/6t3BHA=
Xref: csiph.com comp.lang.c:144417
Ben Bacarisse writes:
> David Brown writes:
>
>> On 04/06/2019 13:20, Ben Bacarisse wrote:
>>
>>> Bart writes:
>>>
>>>> On 04/06/2019 07:56, Ike Naar wrote:
>>>>
>>>>> On 2019-06-03, Bart wrote:
>>>>>
>>>>>> Using a void* to store a void(*)(void) is not a big deal, you
>>>>>> don't want -pedantic-errors to stop your build because of it.
>>>>>
>>>>> Using a function pointer (and not an object pointer) to store a
>>>>> function pointer isn't a big deal either.
>>>>
>>>> How would you create the following table:
>>>>
>>>> void fn1(void){}
>>>> void fn2(int a){}
>>>> void fn3(int a,double b){}
>>>> int fn4(void){return 0;}
>>>> char* fn5(double a){return "";}
>>>>
>>>> void* table[] = {fn1,fn2,fn3,fn4,fn5};
>>>>
>>>> Suggestions to use void(*)(void) for the table element aren't as good.
>>>
>>> As good as what?
>>
>> As good as his incorrect and unsafe code?
>>
>>>> (Because you could actually write table[3]() without the compiler
>>>> picking that up.
>>>
>>> You simply can't do that in C. If that is a deal-breaker, you need a
>>> different language.
>>
>> You can, but you need to wrap things up a bit.
>
> No you can't. There are various ways to handle the different
> function types, but none of them pick up an invalid call as Bart
> wants. In every method I can think of you, the programmer, must
> state the correct type at (or possible at some time before) the
> time of the call. I.e. its up to you to get it right.
>
>> Something like this would work:
>>
>> typedef void (*fvoid)(void);
>> typedef union {
>> void (*v_v)(void);
>> void (*v_i)(int);
>> void (*v_id)(int, double);
>> int (*i_v)(void);
>> char* (*pc_d)(double);
>> } fvoids;
>>
>> fvoids table1[] = {{(fvoid) fn1}, {(fvoid) fn2}, {(fvoid) fn3},
>> {(fvoid) fn4}, {(fvoid) fn5}};
>>
>> fvoids table2[] = {{.v_v = fn1}, {.v_i = fn2}, {.v_id = fn3},
>> {.i_v = fn4}, {.pc_d = fn5}};
>>
>>
>> void foo(int x) {
>> table1[1].v_i(x);
>> }
>
> But Bart wants to write table[n]() and so on.
Does he? I thought he wanted _not_ to be able to write calls in
that form (ie, that if written they would be flagged by the
compiler).
> As for using a union, I am not sure it carries its weight. It
> seems simple enough just to cast at the point of call, and not
> much more wordy if you define typedefs rather than union members:
>
> ((v_i_ftype)table[1])(x);
An advantage of the union method (with the table2 scheme) is that
no casts are required. The appropriate member needs to be
accessed in calling the function, but if that is done then
everything else is type safe and cast free.
> This is well-defined (provided you get the type right) but I am
> not 100% sure the union is. Does C guarantee that the
> bit-representation of all function pointer types must be the
> same? You'll probably get away with it, but I don't think the
> compiler /has/ to play ball.
ISO C certainly does not guarantee that all function pointer
types have the same representation, or even that they have the
same size. The table2 initialization method, together with using
table2 rather than table1 in the foo() functions (and assuming I
haven't missed something), works fine. The table1 scheme is an
accident waiting to happen -- ie, undefined behavior, and not
the nice kind either like passing a negative int for an unsigned
int. In all likelihood (famous last words), it will probably
work, but certainly there is no guarantee that it will.