Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]


Groups > comp.lang.c > #45740

Re: Is this a compiler bug? (Function accepts *ptr when **ptr is specified)

From jt@toerring.de (Jens Thoms Toerring)
Newsgroups comp.lang.c
Subject Re: Is this a compiler bug? (Function accepts *ptr when **ptr is specified)
Date 2014-06-10 09:38 +0000
Organization Freie Universitaet Berlin
Message-ID <bvo20tFb7itU1@mid.uni-berlin.de> (permalink)
References <p4pcp95g1suo33d9s89u212mv8belco8oe@4ax.com>

Show all headers | View raw


DSF <notavalid@address.here> wrote:
>   I have some code that compiles with no errors/warnings that would
> seem to me to have an error.

>   I have four variations on a function called ReadTextFile_XX. (XX
> representing the four variations.)  Each of them reads the file into a
> large buffer and then parses it into a structure containing, among
> other things, an array of strings.  One for each line of the file.

>   The variations involve character size, 8-8, 8-16, 16-8, 16-16.   
>   A pointer to a callback function to display progress is passed to
> each of them.  If it's NULL, the pointer is set to a stub that does
> nothing, else it's left alone.

>   I noticed the four functions had quite a bit of redundancy (the
> parts that reads the file into a large buffer were identical), so I
> separated that code into a function called ReadTextFileCommon.  The
> entire code would be too large, so here are the highlights:

> TEXTFILEDATAA is the structure.
> int64 is a 64 bit int.
> DWORD is an unsigned long (same as unsigned int, here).

> For the callback routine.
> typedef int (*RTFDPR)(int type, DWORD filecount, DWORD filesize);

>   The common function takes a pointer to the address of the pointer
> for the callback routine because it takes care of the NULL to stub
> conversion, if needed.

Dealing with NULL is no sufficient reason for passing a pointer
to a function pointer - a function pointer can be NULL. You
only need to pass a pointer to the function pointer if you
need to know in the caller which function actually was used.

> The common function reads the file by size,
> not characters.  This is why filebuffer is a void pointer and
> TEXTFILEDATAW can be cast to TEXTFILEDATAA because the common function
> doesn't use the text-based parts of the structure.

> bool ReadTextFileCommon(TEXTFILEDATAA *tfd, int64 *filesize, void
> **filebuffer, void **progress);

Even if you need to pass a pointer to the function pointer,
why not use the correct pointer type? I.e.

   bool ReadTextFileCommon( TEXTFILEDATAA  *tfd,
                            int64          *filesize,
                            void          **filebuffer,
                            RTFDPR         *progress );

That still allows you to do

   RTFDPR callback = NULL;   /* or a pointer to an existing function */
   ReadTextFileCommon(tfd, &filesize, filepuffer, &callback);

but won;t keeo the compiler from complaining if what you pass
as the last argument hasn't the proper type, i.e. a pointer to
an appropriate typed function pointer.

> {
>   RTFDPR DisplayProgress;
> ...
> rtfdpr is the stub.
>   if(*progress == NULL)
>     *progress = rtfdpr;
>   DisplayProgress = *progress;
> ...
> }

But if the caller doesn't need to know which callback routine
was actually used in ReadTextFileCommon() if none was requested
you'd better just use

   bool ReadTextFileCommon( TEXTFILEDATAA  *tfd,
                            int64          *filesize,
                            void          **filebuffer,
                            RTFDPR          progress );

(RTFDPR already *is* a pointer!) and call it like this (or
with the callback function to use instead of NULL):

   ReadTextFileCommon(tfd, &filesize, filepuffer, NULL);

and in ReadTextFileCommon you can then simply do

   if ( ! progress )
       progress = rtfdpr;

> Read 8, output 16.
> void ReadTextFile_AW(TEXTFILEDATAW *tfd, uint start, uint end, uint
> codepage, void *progress)
> {
> ...
> Passes the address of progress to the common routine.
>   if(ReadTextFileCommon((TEXTFILEDATAA *)tfd, &filesize, (void
> **)&filebuffer, &progress) == false)
>     return;
> ...
> }

> Read 16, output 16.
> void ReadTextFile_WW(TEXTFILEDATAW *tfd, uint start, uint end, void
> *progress)
> ...
> I hadn't modified this code yet to take into account the pointer to
> the address of the progress function pointer.  Note no & before
> progress in the call.

Yup, that's not a good idea, especially when you do that with
void pointers as Barry Schwarz already pointed out;-)

>   if(ReadTextFileCommon((TEXTFILEDATAA *)tfd, &filesize, (void
> **)&filebuffer, progress) == false)
>     return;
> ...
> }

Mmmm, too many casts here for my liking. Since you don't show
what the structures TEXTFILEDATAW and TEXTFILEDATAA are and how
they're used in your ReadTextFileCommon() function it's
impossible to say if this can work. Unless the two types of
structures differ only in that TEXTFILEDATAW has some addi-
tional members at the end then there's a high chance for
things to go wrong. I'd think about making the TEXTFILEDATAA
data structure a part of the TEXTFILEDATAW structure (or make
up a structure of those parts they have in common - you can't
use anything else than that in ReadTextFileCommon() anyway) and
pass this common part to ReadTextFileCommon(). That avoids having
to cast and thereby keeping the compiler from helping you if you
try to do something fishy.

The way you pass 'filebuffer' also seems odd. Since you pass a
pointer to a pointer I would guess that you do that to allocate
memory for it within ReadTextFileCommon() (otherwise, why pass
a pointer to a pointer you can't dereference?). But for that in
the ReadTextFileCommon() there's not enough information about
the real type to do the allocation - you can't allocate voids
and you don't know what type it has in the caller...

I'm just can guess that in ReadTextFileCommon() you actually read
in the data from the file and allocate a sufficiently large
buffer for those data - otherwise why pass in a pointer to
a pointers to the destination buffer and a pointer for the file
size? But then it would make more sense to pass perhaps a char**
to the function, for which it allocates enough memory (as many
chars as filesize holds in the end, I presume) and do the casting
back in the caller, which actually knows how it wants to interpret
the "raw" data.
                         Regards, Jens
-- 
  \   Jens Thoms Toerring  ___      jt@toerring.de
   \__________________________      http://toerring.de

Back to comp.lang.c | Previous | NextPrevious in thread | Next in thread | Find similar | Unroll thread


Thread

Is this a compiler bug? (Function accepts *ptr when **ptr is specified) DSF <notavalid@address.here> - 2014-06-09 22:46 -0400
  Re: Is this a compiler bug? (Function accepts *ptr when **ptr is specified) Barry Schwarz <schwarzb@dqel.com> - 2014-06-09 21:16 -0700
  Re: Is this a compiler bug? (Function accepts *ptr when **ptr is specified) jt@toerring.de (Jens Thoms Toerring) - 2014-06-10 09:38 +0000
  Re: Is this a compiler bug? (Function accepts *ptr when **ptr is specified) Richard Damon <Richard@Damon-Family.org> - 2014-06-10 07:19 -0400
  Re: Is this a compiler bug? (Function accepts *ptr when **ptr is specified) Ralf Damaschke <rwspam@gmx.de> - 2014-06-10 23:02 +0000
  Re: Is this a compiler bug? (Function accepts *ptr when **ptr is specified) Ike Naar <ike@iceland.freeshell.org> - 2014-06-11 05:56 +0000
    Re: Is this a compiler bug? (Function accepts *ptr when **ptr is specified) gazelle@shell.xmission.com (Kenny McCormack) - 2014-06-11 09:39 +0000
  Re: Is this a compiler bug? (Function accepts *ptr when **ptr is specified) DSF <notavalid@address.here> - 2014-06-11 23:52 -0400
    Re: Is this a compiler bug? (Function accepts *ptr when **ptr is specified) Barry Schwarz <schwarzb@dqel.com> - 2014-06-11 22:38 -0700
    Re: Is this a compiler bug? (Function accepts *ptr when **ptr is specified) James Kuyper <jameskuyper@verizon.net> - 2014-06-12 07:45 -0400

csiph-web