One more thing to keep in mind for the c to c++ conversion... The c++ compiler is stricter on some type checking. You will have to make real code changes to allow it to compile some c code. Those changes are not significant, but do have to be correct and verified. At least that is what happened when I did this for some test driver source files.
Stefan On Fri, Feb 6, 2026 at 9:28 AM <[email protected]> wrote: > John, thank you for your detailed reply. > I've responded inline below > If you are still unconvinced please say so and I'll abandon this. > Thanks again. > - russ > > > -----Original Message----- > > From: John Ralls <[email protected]> > > Sent: Thursday, February 5, 2026 9:04 PM > > To: [email protected] > > Cc: [email protected] > > Subject: Re: exception fencing > > > > > > > > > On Feb 5, 2026, at 3:03 PM, <[email protected]> > > <[email protected]> wrote: > > > > > > Since this is my first attempt to submit code to the GNC project I > > > thought I’d pass my approach through the established developers first. > > > I am interested in converting GNC code from C to C++ which will occur > over > > time so that the review quanta is not too overwhelming. > > > I plan to convert build targets to only use the C++ compiler over time. > > > Anything that is exposed with C linkage I plan to carry forward > expecting at > > some point all the callers will be C++ as well and most if not all of > the C- > > linkage requirements will go away. > > > Any C++ code that is called from C-code will need a mechanism to > prevent > > C++ exceptions from bleeding back. > > > I’ve developed a header file except-fence.hpp that provides the > required > > fencing. > > > My first patch will be just this header file and the associated test > files, so no > > GNC code will be affected initially. > > > I wanted to make the footprint small since I expect the fences will > eventually > > be removed. > > > My approach is to replace the definition if the C-API functions with a > > > macro that defines a stub C-API (extern “C”) Which instantiates an > > ExceptFence object and uses the “forward_to” method call a local static > > function with the original body. > > > For Example: > > > const char * > > > func1(int a, gpointer b) // defined as extern “C” in header file { … } > > > Becomes: > > > SAFE_C_API_ARGS(const char *, func1, (int a, gpointer b), (a, b)) { … > > > } Which (essentially) expands to: > > > static const char *loc_func1(int a, gpointer b); extern “C” const > > > char *func1(int a, gpointer b) { > > > ExceptFence exf; > > > return exf.forward_to(loc_func1, a, b); } static const char > > > *loc_func1 (int a, gpointer b) { … } > > > The essence of forward_to is the following: > > > template<typename Func, typename... Args> > > > auto forward_to(Func&& func, Args&&... args) > > > { > > > try { > > > m_except_data.exception_hit = true; > > > auto result = func(std::forward<Args>(args)...); > > > m_except_data.exception_hit = false; > > > return result; > > > } > > > catch (const std::exception& ex) { > > > m_except_data.exception_type = &typeid(ex); > > > m_except_data.exception_message = ex.what(); > > > } > > > using ReturnType = std::invoke_result_t<Func, Args...>; > > > if constexpr (std::is_integral_v<ReturnType>) { > > > return > static_cast<ReturnType>(m_exception_error_integer); > > > } else if constexpr (std::is_pointer_v<ReturnType>) { > > > return static_cast<ReturnType>(nullptr); > > > } else { > > > return ReturnType{}; > > > } > > > } > > > This definition of forward_to() supports functions that return > integer types, > > pointer types, and structure types. > > > That appears to support most of what we need that I’ve seen. > > > There are 4 different SAFE_C_API macros to support all the > combinations of > > void args and void return types. > > > Anyway, if there are concerns about this approach, or request for more > > details please let me know. > > > Thanks for your attention and support. > > > > Getting rid of C entirely requires changing the GUI framework; the > minimum > > effort would be gtkmm but even that will be a lot of work. It isn’t > going to > > happen any time soon. > > [russ] I figured there might be some elements that are impractical to > convert > But I still think it makes sense to enable C++ coding in the main. There > are just a lot > A nice features of C++ that would be good to take advantage of. > > > Also to consider is that exceptions either can’t be > > allowed to leak through the Python and Scheme bindings or those bindings > > need to acquire exception converters. > > [russ] Yeah I thought that the binding interfaces would need to remain as > C-Linkage but can still be C++ code underneath. > > > > > Just switching to compiling C code with a C++ compiler doesn’t introduce > > exceptions so the need to wrap calls in try/catch is limited to cases > when the > > function is reimplemented to use some C++ thing that throws. > > [russ] right but the code will be available for use of C++ constructs by > developers but still callable from C compilation units > > > Note that > > loc_func1 still has to check ext.m_except_data.exception_hit and if it’s > true do > > something with the rest. I suspect that that something will turn out to > be > > sufficiently not generic that having the template won’t really save much > over > > just catching the exception in the implementation function or writing a C > > wrapper that handles exceptions in a way that’s appropriate for the > execution > > context at hand. > > [russ] I'm not sure I agree completely. The fence is only for catching > unhandled exceptions (coding bugs), and the fence is in func1(), but the > implementation logic is in loc_func1(). Even carefully designed C++ can > have unusual circumstance that result in an unexpected exception. If there > is any cleanup that needs to be done (beyond returning some error value), > that will need to be done with a try/catch in loc_func1(). For functions > that generate a lot of side effects and have complicated unwind logic its > likely they won't be able to do that with a giant catch-all at the top > anyway and need layers of try/catch to properly deal with them. I agree > that if we mandate a giant catch-all at the top of all the C-APIs when > implementing that might work for catching everything but in my experience > its tricky to get right and error prone. E.g. if we instantiate an object > before the try, those constructors can throw unprotected. > > > > > BTW, “m_exception_error_integer” is a problem because it implies that > that’s > > a single value used for all cases and it’s not hard at all to think of > cases where > > different values would be needed for signaling an error. > > [russ] in the implementation of ExceptFence, the constructor can take any > integer value and use that as the error value for integer return types. But > you are right that the macros don't currently support that, but that would > be easy to change. From what I've seen so far the return types for these > APIs in the code base are either some kind of integer, some kind of > pointer, or some kind of structure. The class currently supports specifying > what the integer error value is for uncaught exceptions, but for the other > return types it currently only supports nullptr/zeroed-out-structure, but > that also could be fixed to support any error value of those types. > > So the exception fence really just ensures that uncaught exceptions return > a known error type and that the implementation function does not need a v. > carefully designed giant catch-all at the top. > > Void functions are tougher. Caught exceptions currently just return and > leave an unknown state behind without any side effects. If there was some > notification possible that would be nice. > > Once nice thing of having the fencing in a single class is if you suspect > an unhandled exception e.g. in a void C-API func, it’s a single breakpoint > in the code. > > > > > > > Regards, > > John Ralls > > > _______________________________________________ > gnucash-devel mailing list > [email protected] > https://lists.gnucash.org/mailman/listinfo/gnucash-devel >
_______________________________________________ gnucash-devel mailing list [email protected] https://lists.gnucash.org/mailman/listinfo/gnucash-devel
