> -----Original Message-----
> From: Joe Wilson [mailto:[EMAIL PROTECTED]
> Sent: Monday, January 22, 2007 5:20 PM
> To: sqlite-users@sqlite.org
> Subject: RE: [sqlite] Fix for sqlite3.h in version 3.3.10
> 
> --- James Dennett <[EMAIL PROTECTED]> wrote:
> > > -----Original Message-----
> > > From: Joe Wilson [mailto:[EMAIL PROTECTED]
> > > Subject: Re: [sqlite] Fix for sqlite3.h in version 3.3.10
> > [snip]
> >
> > > > I don't know if this is the right place to post suggestions to
the
> > > > SQLite developers, but why don't you do something like
> > > > #define SQLITE_COMPAT_MODE
> > > > and do these things like making SQLITE_TRANSIENT point to real
> > > > function under #ifndef SQLITE_COMPAT_MODE? So the older users
can
> > > > compile under SQLITE_COMPAT_MODE and avoid having problems,
while
> > > > newly written code can rely on proper, clean code?
> > >
> > > By whose definition of proper code?
> >
> > The ANSI/ISO C and C++ committees, and the standards produced by
them.
> 
> Please cite the passage in either the C or C++ standards.

There are two issues: the linkage issue, and the undefined nature of the
conversion from an int to a function pointer type.  

The linkage issue is certainly spelled out in normative text in the C++
standard; see primarily the section "Linkage specifications" [dcl.link].
The section number in N2135 is 7.5; I don't have the IS handy to see if
that's changed (likely it has).

Regarding the undefined nature of the conversion in question, I'd have
to check to see whether it's explicitly called out as undefined, or
whether it is simply undefined because nothing defines it.  Even casting
-1 to an (int*) is not portable, to allow for systems where alignment
requirements are enforced at conversion time among other things.

> The proposed expression ((sqlite3_destructor_type)-1) is equivalent to
> ((void(*)(void *))-1). They are interchangable.

Not in C++.  The difference being linkage; with the typedef declared in
an extern "C" block, the type is something that can't be written
directly.  The types named by the following two typedefs are not the
same:

extern "C" { typedef void(*has_c_linkage)(void*); };
typedef void(*has_cpp_linkage)(void*);

This issue doesn't affect C.

> > > It would be a lot of effort to "solve" a problem that does not
exist.
> > >
> > > >>>> which is diagnosed, though only as a warning, by Sun CC
> > >
> > > It's just a harmless warning produced by the cast when compiled by
> > > a certain overly pedantic C++ compiler.
> >
> > No; the type mismatch is a real problem that can cause real crashes
with
> > valid C++ compilers, in the case that C and C++ use different
calling
> > conventions.
> >
> > > The proposed typedef offered
> > > by the original poster seems like a reasonable appeasement:
> > >
> > >  -#define SQLITE_STATIC      ((void(*)(void *))0)
> > >  -#define SQLITE_TRANSIENT   ((void(*)(void *))-1)
> > >  +typedef void (*sqlite3_destructor_type)(void*);
> > >  +#define SQLITE_STATIC      ((sqlite3_destructor_type)0)
> > >  +#define SQLITE_TRANSIENT   ((sqlite3_destructor_type)-1)
> > >
> > > But the typedef should not be required.
> >
> > In C++, it is required to give the function pointer the correct
type.
> 
> Please show the source code that produces this Sun C++ compiler
warning
> with the exact text of the warning.

Here is a small example program:

extern "C" { typedef void(*has_c_linkage)(void*); }
typedef void(*has_cpp_linkage)(void*);

void fn_c(has_c_linkage a);
void fn_cpp(has_c_linkage a);

void sample_with_cpp_linkage(void*) {}
extern "C" void sample_with_c_linkage(void*) {}

int main()
{
    fn_c(sample_with_c_linkage);
    fn_cpp(sample_with_cpp_linkage);

    fn_cpp(sample_with_c_linkage);
    fn_c(sample_with_cpp_linkage);
}

The result of compiling with Sun CC is:
"linkage.cpp", line 13: Warning (Anachronism): Formal argument a of type
extern "C" void(*)(void*) in call to fn_cpp(extern "C" void(*)(void*))
is being passed void(*)(void*).
"linkage.cpp", line 16: Warning (Anachronism): Formal argument a of type
extern "C" void(*)(void*) in call to fn_c(extern "C" void(*)(void*)) is
being passed void(*)(void*).
2 Warning(s) detected.

Comeau's C++ compiler is widely viewed as a paragon of compliance, being
based on the excellent EDG frontend.  It offers similar diagnostics:

bash-2.05$ como -A linkage.cpp
"linkage.cpp", line 13: error: argument of type "void (*)(void *)" is
          incompatible with parameter of type "has_c_linkage"
      fn_cpp(sample_with_cpp_linkage);
             ^

"linkage.cpp", line 16: error: argument of type "void (*)(void *)" is
          incompatible with parameter of type "has_c_linkage"
      fn_c(sample_with_cpp_linkage);
           ^
> > Any C++ compiler that does not issue a diagnostic for this fails to
> > conform to the C++ standard in this regard (which is not to say that
> > such compilers are uncommon).
> 
> You're making the assumption that Sun's C++ compiler warning is
correct
> in this case.

No, I am not; I happen to know that it is correct, and I'm using the
compiler warning as one way to communicate with people who also
understand the rules.  I see that I will need to be more explicit as
this situation is not widely understood.
 
> Should Sun change their definitions of the following as well?

Probably not, for reasons given below.

>   #define SIG_IGN (void(*)(int))1
>   #define SIG_ERR (void(*)(int))-1
> 
> Such C code is grandfathered in C++. If it wasn't you wouldn't be able
> to do any UNIX systems programming in C++.

It's not portable C, and it's not portable C++.  It does seem to be
blessed by POSIX, but POSIX is just a subset of the much larger range of
platforms supported by ISO/ANSI C and C++.

Sun is the implementor, they're not writing portable code; they control
the OS, the compilers, the standard library.  They can write
non-portable code as much as they like.  Sometimes it's necessary, and
sometimes the cost of making code more portable is not a sensible
business decision.  The cost to us to improve this trivial aspect of
SQLite is small though, and I've seen no argument against it (apart from
the backwards compatibility issue, which is easily addressed in the
implementation while allowing a portable interface).  Naturally the fact
that Sun writes certain code, or issue a particular warning, doesn't
mean that it's right; it doesn't mean that it's wrong either.

-- James


-----------------------------------------------------------------------------
To unsubscribe, send email to [EMAIL PROTECTED]
-----------------------------------------------------------------------------

Reply via email to