From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from srv01.pe82.de (unknown [IPv6:2a01:4f8:1c0c:5bed::2]) by sourceware.org (Postfix) with ESMTPS id 362F93858C00 for ; Fri, 27 Jan 2023 14:29:10 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 362F93858C00 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=pe82.de Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=pe82.de Received: from [10.99.2.11] (p5799dbcd.dip0.t-ipconnect.de [87.153.219.205]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by srv01.pe82.de (Postfix) with ESMTPSA id 5C97F7D30E for ; Fri, 27 Jan 2023 15:29:08 +0100 (CET) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=pe82.de; s=dkim; t=1674829748; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=ojhLcXzw/PAFsUwJQnt/pF/CFR95DC6sXQbrAM0ZhvA=; b=J4ouW/gPIy8OX73rHRnPU+RCEYVa157uDWFCHxIHbxQWO6C82DefnmTyOhvYNmJzAOMuQG SxaFregBl+wqDViXDS0IjrHkFtvpUOwgj+pT9lYDrPk6MfgjbFlwZOA6iI6xIaVwcAM/BQ u3QSC1bMP0Z2EWe8JoC9/eqEzDj0bds= From: Michael Pape To: gcc-help@gcc.gnu.org Subject: Re: Correct way to provide a C callback function nside C++ Date: Fri, 27 Jan 2023 15:29:07 +0100 X-Mailer: MailMate (1.14r5918) Message-ID: In-Reply-To: References: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-2.1 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,KAM_SHORT,SPF_HELO_NONE,SPF_PASS,TXREP autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: On 27 Jan 2023, at 15:07, Jonathan Wakely wrote: > On Fri, 27 Jan 2023 at 13:24, Pepe via Gcc-help = wrote: >> >> Hi there, >> >> I=E2=80=99m in an ongoing discussion about whether or not one should u= se extern =E2=80=9CC=E2=80=9D when defining a function that will be used = as a callback in a statically linked C library. For example: >> >> c_func.h: >> // =E2=80=A6 >> void reg_callback(void (*fn)()); >> // =E2=80=A6 >> >> cpp_impl.cpp: >> // =E2=80=A6 >> extern =E2=80=9CC=E2=80=9D { >> #include =E2=80=9Cc_func.h=E2=80=9D >> } >> >> // my callback function with internal linkage >> namespace { >> >> extern =E2=80=9CC=E2=80=9D { >> static void my_callback_A() { >> // =E2=80=A6 >> } >> } // extern =E2=80=9CC=E2=80=9D >> >> void my_callback_B() { >> // =E2=80=A6 >> } >> >> } // namespace >> >> void do_something() { >> reg_callback(my_callback_A); >> reg_callback(my_callback_B); >> } >> >> Both callbacks have internal linkage. Both work fine, and something li= ke my_callback_B is found in lots of code bases. >> >> In my opinion, using callback B is implementation defined behaviour, b= ecause it is not guaranteed that C and C++ use the same calling conventio= ns. Therefore a function must adhere to the C calling conventions to be u= sed as a callback in a C library, which would be callback A. >> >> I=E2=80=99ve been trying to find something definitive for days now, bu= t to no avail. Now I=E2=80=99m not sure what=E2=80=99s true or not. The c= ounter argument is the following: The compiler should know reg_callback i= s a C function and make sure that a given argument would either be valid = or cause a compiler error. That sounds reasonable, so I would love to kno= w how to do it properly for future reference. Given we use gcc I was hopi= ng to get a definitive answer in this mailing list. Thanks a lot! > > You are (mostly) correct. The C++ standard says that extern "C" > functions and extern "C++" functions have different types, and so this > should not even compile: > > extern "C" { > using callback =3D void(*)(); > void f(callback); > } > > void g() { }; > void h() { f(g); } > > There should be a compilation error when trying to pass g (which is an > extern "C++" function) to f (which accepts a pointer to an extern "C" > function). > > GCC (and most other compilers) do not actually conform to that > requirement in the standard, and the types are identical. Which means > there is no compilation error, and the code works fine. > > I think it's safe to assume that *either* the code compiles and works > as expected, or fails to compile. And in practice it compiles and > works with all widely used compilers. You will not find a C++ > implementation where the types are not compatible, but the code > compiles anyway and then misbehaves at runtime. > > The relevant GCC bug about this nonconformance is > https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D2316 (and will probably > never be fixed, because it would break far too much code). > > The relevant quote from the C++ standard is in [dcl.link]: > "The default language linkage of all function types, functions, and > variables is C ++ language linkage. Two function types with different > language linkages are distinct types even if they are otherwise > identical." > > Being distinct types means that there should be not implicit > conversion from &g in the example above to the type callback. An > explicit conversion (e.g. using reinterpret_cast) would be allowed, > but then it would be undefined behaviour to actually call the function > g() through a pointer to a different function type. In practice, that > isn't a problem because they're not distinct types with GCC, so the > code works. > > > > > > Thank you very much, that perfectly answered my question :) >> >> Pepe