模块/语言边界上的异常传播 [英] propagation of exceptions over module/language boundaries

查看:55
本文介绍了模块/语言边界上的异常传播的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述




我希望你会看到这个交叉帖子(c / c ++)。我也立即承认

,问题*可能*结果是

编译器 - / os-特定,在这种情况下我道歉。但我想知道是否有一个潜在的事实。


我们正在编写一个(跨平台)''框架''应用程序(用C ++编写) ,因为它发生了允许用户创作''插件''(作为共享库

模块)。由于插件的生命周期预计很长,并且可以使用更新的编译器版本更新

框架,因此我们选择了

来为这些插件提供C接口避免更改问题

ABIs(据我所知)。插件预计将导出

单个未修饰函数Event(EventData * data),并可通过从
到框架/>
一个API模块,''api'',也是用C ++编写的。通常,

框架将加载一个插件,调用它的Event()函数,并且

函数将调用API上的这些回调函数之一。 />

此时我必须拥有并说我不完全理解链接

或调用约定,所以当我说我们提供一个C时接口"我所说的是,b $ b意味着api被编译为导​​出其未修饰的函数(使用externC排序

,但实际上还有其他一些东西

继续我不想进入,所以我希望这是一个很好的近似值 - api是一个C ++模块但它的出口

未修饰)。此外,插件将其Event()函数导出为ex​​ternC。


动机:如果api可以抛出异常将会很方便

该框架将承认。它可以毫不费力地通过

任何用户代码而无需用户做任何事情,而框架

可以找出发生了什么并生成有用的错误报告。

替代方案是我们强制执行所有API函数不抛出并且

而不是返回错误代码 - 然后在插件作者上有责任

捕获错误并将其返回到框架(或者,如果它们是用C ++编写的
,他们可以自己抛出异常,但我不是

确定这是不是同一个问题。


现在,''api''是用C ++编写的,框架也是如此,但是用户插件

可以用C或C ++编写(或者,实际上,任何其他语言都可以满足接口的要求)。所以我最初的想法是

我们不能使用异常,就像他们是伟大的imho一样。但是,在我的

当前开发副本中,我发现异常工作正常。我担心在

我当前的开发副本我正在编译框架,api,*和*测试

插件,都使用相同的编译器(cl v14,赢得xp),这可能会隐藏

一旦我们进行更多混合匹配就会出现的问题。另外,

我正在用C ++编写这个特殊的插件,所以一切都是C ++保存

实际导出的函数声明。


所以...问题是,我们应该避免在这些模块边界上抛出异常,还是可以这样做?我实际上可以通过安装其他一些编译器来测试这一点,但是我认为

无论如何都不会是一个彻底的测试,所以我宁愿达成一些

的理解。例如......


*框架加载"插件>

*框架调用插件::事件()

*插件调用api :: Sum()

* Sum()中出现错误情况

* Sum()抛出类型X的异常


或者,换句话说,调用堆栈看起来像:


framework :: main()(C ++)

--plugin: :事件()(C)

--api :: Sum()(C ++)

扔X;


现在,如果X是一个int,它会在所有情况下安全地通过插件

通过,即使插件编译为(旧的,可能)C

编译器严格意识不到异常?这是一个

编译器/特定于OS的问题吗?如果X是在api.h中定义的C结构怎么办?


从我学到的关于异常及其实现方式的知识,

我不喜欢立即看到以这种方式传递一个''到''

异常 - 不知道代码的问题。在与C代码相关的

堆栈上将没有处理程序,但我想这意味着

控件将直接从(有效)通过扔声明

api to thecatch在框架中阻止。但是我很担心堆栈的安排方式是为了容纳两个跨模块边界调用

会以某种方式干扰这种机制。我也担心当它到达框架时,对象的

类型将无法被识别 - 我可以使用const char *作为异常类型's $

唯一可靠的选项,但当然,带有代码,消息和一些

源信息的结构将更可取。


Phew。我希望'很清楚。


提前感谢任何评论。

Ben Mitch

解决方案

ben mitch写道:





我希望你会看到这个十字架-post(c / c ++)视情况而定。我也立即承认

,问题*可能*结果是

编译器 - / os-特定,在这种情况下我道歉。但我想知道是否有一个潜在的事实。


我们正在编写一个(跨平台)''框架''应用程序(用C ++编写) ,因为它发生了允许用户创作''插件''(作为共享库

模块)。由于插件的生命周期预计很长,并且可以使用更新的编译器版本更新

框架,因此我们选择了

来为这些插件提供C接口避免更改问题

ABIs(据我所知)。插件预计将导出

单个未修饰函数Event(EventData * data),并可通过从
到框架/>
一个API模块,''api'',也是用C ++编写的。通常,

框架将加载一个插件,调用它的Event()函数,并且

函数将调用API上的这些回调函数之一。 />

此时我必须拥有并说我不完全理解链接

或调用约定,所以当我说我们提供一个C时接口"我所说的是,b $ b意味着api被编译为导​​出其未修饰的函数(使用externC排序

,但实际上还有其他一些东西

继续我不想进入,所以我希望这是一个很好的近似值 - api是一个C ++模块但它的出口

未修饰)。另外,插件将他们的Event()函数导出为ex​​tern

C。


动机:如果api可以抛出异常会很方便<框架可识别的
。它可以毫不费力地通过

任何用户代码而无需用户做任何事情,而框架

可以找出发生了什么并生成有用的错误报告。

替代方案是我们强制执行所有API函数不抛出并且

而不是返回错误代码 - 然后在插件作者上有责任

捕获错误并将其返回到框架(或者,如果它们是用C ++编写的
,他们可以自己抛出异常,但我不是

确定这是不是同一个问题。


现在,''api''是用C ++编写的,框架也是如此,但是用户插件

可以用C或C ++编写(或者,实际上,任何其他语言都可以满足接口的要求)。所以我最初的想法是

我们不能使用异常,就像他们是伟大的imho一样。但是,在我的

当前开发副本中,我发现异常工作正常。我担心在

我当前的开发副本我正在编译框架,api,*和*测试

插件,都使用相同的编译器(cl v14,赢得xp),这可能会隐藏

一旦我们进行更多混合匹配就会出现的问题。另外,

我正在用C ++编写这个特殊的插件,所以一切都是C ++保存

实际导出的函数声明。


所以...问题是,我们应该避免在这些模块边界上抛出异常,还是可以这样做?我实际上可以通过安装其他一些编译器来测试这一点,但是我认为

无论如何都不会是一个彻底的测试,所以我宁愿达成一些

的理解。例如......


*框架加载"插件>

*框架调用插件::事件()

*插件调用api :: Sum()

* Sum()中出现错误情况

* Sum()抛出类型X的异常


或者,换句话说,调用堆栈看起来像:


framework :: main()(C ++)

--plugin: :事件()(C)

--api :: Sum()(C ++)

扔X;


现在,如果X是一个int,它会在所有情况下安全地通过插件

通过,即使插件编译为(旧的,可能)C

编译器严格意识不到异常?这是一个

编译器/特定于OS的问题吗?如果X是在api.h中定义的C结构怎么办?


从我学到的关于异常及其实现方式的知识,

我不喜欢立即看到以这种方式传递一个''到''

异常 - 不知道代码的问题。在与C代码相关的

堆栈上将没有处理程序,但我想这意味着

控件将直接从(有效)通过扔声明

api to thecatch在框架中阻止。但是我很担心堆栈的安排方式是为了容纳两个跨模块边界调用

会以某种方式干扰这种机制。我也担心当它到达框架时,对象的

类型将无法被识别 - 我可以使用const char *作为异常类型's $

唯一可靠的选项,但当然,带有代码,消息和一些

源信息的结构将更可取。


Phew。我希望'很清楚。


提前感谢任何评论。

Ben Mitch



我在动态生成的C代码的背景下广泛研究了这个问题。我不会厌烦你的细节,但解决你看到的问题根本不容易。


1)使用Microsoft编译器将会有效客户也使用

相同的编译器和相同的版本。使用不同版本的

编译器可能会发生变化,你会遇到神秘的

崩溃。


2)尽可能避免使用gcc 。几乎没有关于

异常框架的文档,并且可用的文档非常具有误导性。在任何情况下,如果你必须使用gcc,你将需要

总是使用gcc(客户端和API服务器),特别是同样的gcc的同样的b $ b版本。请记住,gcc将其行为从

版本更改为版本而没有任何公告,因为所有这些都是

没有真正记录。

-

jacob navia

jacob at jacob point remcomp point fr

logiciels / informatique
http://www.cs.virginia.edu/~lcc-win32


ben mitch< ne ** @ benmitch.netwrites:


我希望你会看到这个交叉帖子(c / c ++ ) 作为适当的。我也立即承认

,问题*可能*结果是

编译器 - / os-特定,在这种情况下我道歉。但我想知道是否

有一个潜在的事实。



[SNIP]


>

动机:如果api可以抛出框架可识别的异常

将会很方便。它可以通过任何用户代码无痛地通过

而无需用户做任何事情,并且

框架可以找出发生了什么并产生有用的错误

报告。另一种方法是我们强制所有API函数都不会抛出而不是返回错误代码 - 然后在

插件作者上有责任捕获错误并将其返回到框架(或者,如果他们在C ++中创作,他们可以抛出异常

自己,但是我不确定这不是'同样的问题)。



[SNIP]


我认为这对comp.lang.c ++来说真的是个问题,不适用于

comp.lang.c(尽管它确实涉及两种语言.C +

标准定义了与C接口的功能,但C没有定义

任何与C ++接口的功能。此外,C没有说什么

关于C ++风格的异常。


我怀疑跨C代码的异常传播是系统-specific,

但comp.lang.c ++中的人可能会在这一点上给你更多信息




-

Keith Thompson(The_Other_Keith) ks***@mib.org < http:// www.ghoti.net/~kst>

诺基亚

我们必须做点什么。这是事情。因此,我们必须这样做。

- Antony Jay和Jonathan Lynn,Yes Minister


2008-06-13 15:07,ben mitch写道:




我希望你会看到这个交叉帖子(c / c ++)。我也立即承认

,问题*可能*结果是

编译器 - / os-特定,在这种情况下我道歉。但我想知道是否有一个潜在的事实。


我们正在编写一个(跨平台)''框架''应用程序(用C ++编写) ,因为它发生了允许用户创作''插件''(作为共享库

模块)。



如果你想让它真正跨平台,你不能允许例外

传递到插件/从插件传递。原因很简单:没有

标准化的方法。唯一可以在多个平台上使用的(?)标准化调用

约定是C

调用约定,它不支持例外。

-

Erik Wikstr ?? m


Hi

I hope you''ll see this cross-post (c/c++) as appropriate. I also admit
immediately that the question *may* turn out to be
compiler-/os-specific, in which case I apologize. But I wonder if
there''s an underlying truth.

We are writing a (cross-platform) ''framework'' application (in C++, as it
happens) that allows users to author ''plugins'' (as shared library
modules). Since the lifetime of plugins is expected to be long, and the
framework may be updated using a later compiler version, we have chosen
to offer a C interface to those plugins to avoid issues with changing
ABIs (as far as I understand it). Plugins are expected to export a
single undecorated function, Event(EventData* data), and may call back
to the framework through a number of undecorated functions exported from
an API module, ''api'', also authored in C++. Commonly, then, the
framework will load a plugin, call its Event() function, and that
function will call one of these callback functions on the API.

At this point I have to own up and say I don''t fully understand linking
or calling conventions, so when I say we "offer a C interface" what I
mean is that api is compiled to export its functions undecorated (sort
of with the use of extern "C", though actually there''s some other stuff
going on that I''d rather not get into so I''m hoping that''s a
sufficiently good approximation - api is a C++ module but its exports
are undecorated). Also, plugins export their Event() function as extern "C".

Motivation: It would be convenient if the api could throw an exception
that the framework would recognise. It would pass painlessly up through
any user code without the user having to do anything, and the framework
could find out what happened and generate a useful error report. The
alternative is that we enforce that all API functions do not throw and
instead return error codes - the onus is then on the plugin author to
catch the error and return it to the framework (or, if they are
authoring in C++, they could throw an exception themselves, but i''m not
sure if that''s not the same question again).

Now, ''api'' is authored in C++, and so is the framework, but user plugins
may be authored in C or C++ (or, in fact, any other language that can
meet the requirements of the interface). So my initial thinking was that
we couldn''t use exceptions, much as they''re great imho. However, in my
current dev copy, i''m finding exceptions work fine. My worry is that in
my current dev copy i''m compiling the framework, the api, *and* the test
plugin, all with the same compiler (cl v14, win xp), which may be hiding
problems that would arise once we go more mix and match. In addition,
I''m writing this particular plugin in C++, so everything is C++ save the
actual exported function declarations.

So... the question is, should we avoid throwing exceptions across these
module boundaries, or is it ok to do so? I could actually test this to
some extent by installing some other compilers, but I''m thinking that
that''s not going to be a thorough test anyway, so I''d rather reach some
understanding. For instance...

* framework loads "plugin"
* framework calls plugin::Event()
* plugin calls api::Sum()
* error condition occurs in Sum()
* Sum() throws exception of type X

or, to put that another way, the call stack looks like:

framework::main() (C++)
--plugin::Event() (C)
--api::Sum() (C++)
throw X;

Now, if X is, say, an int, will it pass safely back up through "plugin"
in all cases, even if plugin is compiled with an (old, perhaps) C
compiler that is strictly not aware of exceptions? Is this a
compiler-/os-specific question? what if X is a C struct defined in api.h?

From what I have learned about exceptions and how they are implemented,
I don''t immediately see a problem with passing one ''through''
exception-unaware code in this way. There will be no handlers on the
stack associated with the C-code, but I''m supposing that this means that
control will just pass (effectively) directly from the "throw" statement
in api to the "catch" block in framework. But I''m worried that the way
the stack is arranged to accomodate the two cross-module-boundary calls
will somehow interfere with this mechanism. I am also worried that the
type of the object will not be recognised when it reaches framework - I
am fine with sticking with const char* as an exception type if that''s
the only reliable option, but a struct with a code, a message, and some
source information would be preferable, of course.

Phew. I hope that''s clear.

Thanks in advance for any comments.
Ben Mitch

解决方案

ben mitch wrote:

Hi

I hope you''ll see this cross-post (c/c++) as appropriate. I also admit
immediately that the question *may* turn out to be
compiler-/os-specific, in which case I apologize. But I wonder if
there''s an underlying truth.

We are writing a (cross-platform) ''framework'' application (in C++, as it
happens) that allows users to author ''plugins'' (as shared library
modules). Since the lifetime of plugins is expected to be long, and the
framework may be updated using a later compiler version, we have chosen
to offer a C interface to those plugins to avoid issues with changing
ABIs (as far as I understand it). Plugins are expected to export a
single undecorated function, Event(EventData* data), and may call back
to the framework through a number of undecorated functions exported from
an API module, ''api'', also authored in C++. Commonly, then, the
framework will load a plugin, call its Event() function, and that
function will call one of these callback functions on the API.

At this point I have to own up and say I don''t fully understand linking
or calling conventions, so when I say we "offer a C interface" what I
mean is that api is compiled to export its functions undecorated (sort
of with the use of extern "C", though actually there''s some other stuff
going on that I''d rather not get into so I''m hoping that''s a
sufficiently good approximation - api is a C++ module but its exports
are undecorated). Also, plugins export their Event() function as extern
"C".

Motivation: It would be convenient if the api could throw an exception
that the framework would recognise. It would pass painlessly up through
any user code without the user having to do anything, and the framework
could find out what happened and generate a useful error report. The
alternative is that we enforce that all API functions do not throw and
instead return error codes - the onus is then on the plugin author to
catch the error and return it to the framework (or, if they are
authoring in C++, they could throw an exception themselves, but i''m not
sure if that''s not the same question again).

Now, ''api'' is authored in C++, and so is the framework, but user plugins
may be authored in C or C++ (or, in fact, any other language that can
meet the requirements of the interface). So my initial thinking was that
we couldn''t use exceptions, much as they''re great imho. However, in my
current dev copy, i''m finding exceptions work fine. My worry is that in
my current dev copy i''m compiling the framework, the api, *and* the test
plugin, all with the same compiler (cl v14, win xp), which may be hiding
problems that would arise once we go more mix and match. In addition,
I''m writing this particular plugin in C++, so everything is C++ save the
actual exported function declarations.

So... the question is, should we avoid throwing exceptions across these
module boundaries, or is it ok to do so? I could actually test this to
some extent by installing some other compilers, but I''m thinking that
that''s not going to be a thorough test anyway, so I''d rather reach some
understanding. For instance...

* framework loads "plugin"
* framework calls plugin::Event()
* plugin calls api::Sum()
* error condition occurs in Sum()
* Sum() throws exception of type X

or, to put that another way, the call stack looks like:

framework::main() (C++)
--plugin::Event() (C)
--api::Sum() (C++)
throw X;

Now, if X is, say, an int, will it pass safely back up through "plugin"
in all cases, even if plugin is compiled with an (old, perhaps) C
compiler that is strictly not aware of exceptions? Is this a
compiler-/os-specific question? what if X is a C struct defined in api.h?

From what I have learned about exceptions and how they are implemented,
I don''t immediately see a problem with passing one ''through''
exception-unaware code in this way. There will be no handlers on the
stack associated with the C-code, but I''m supposing that this means that
control will just pass (effectively) directly from the "throw" statement
in api to the "catch" block in framework. But I''m worried that the way
the stack is arranged to accomodate the two cross-module-boundary calls
will somehow interfere with this mechanism. I am also worried that the
type of the object will not be recognised when it reaches framework - I
am fine with sticking with const char* as an exception type if that''s
the only reliable option, but a struct with a code, a message, and some
source information would be preferable, of course.

Phew. I hope that''s clear.

Thanks in advance for any comments.
Ben Mitch

I have studied this problem extensively in the context of dynamically
generated C code. I will not bore you with the details, but solving
the problem you see is not easy at all.

1) Using Microsoft compiler will work if all the "clients" use also
the same compiler AND the same version. With different versions of
the compiler things could change and you would experience mysterious
crashes.

2) Avoid gcc if possible. There is no documentation almost about the
exception framework and the documentation available is highly
misleading. In any case if you have to use gcc you will want to
ALWAYS use gcc ("clients" and API server) and specially, the SAME
version of gcc. Do remember that gcc changes its behaviour from
version to version without any announcement, since all this is
not really documented.
--
jacob navia
jacob at jacob point remcomp point fr
logiciels/informatique
http://www.cs.virginia.edu/~lcc-win32


ben mitch <ne**@benmitch.netwrites:

I hope you''ll see this cross-post (c/c++) as appropriate. I also admit
immediately that the question *may* turn out to be
compiler-/os-specific, in which case I apologize. But I wonder if
there''s an underlying truth.

[SNIP]

>
Motivation: It would be convenient if the api could throw an exception
that the framework would recognise. It would pass painlessly up
through any user code without the user having to do anything, and the
framework could find out what happened and generate a useful error
report. The alternative is that we enforce that all API functions do
not throw and instead return error codes - the onus is then on the
plugin author to catch the error and return it to the framework (or,
if they are authoring in C++, they could throw an exception
themselves, but i''m not sure if that''s not the same question again).

[SNIP]

I think this is really a question for comp.lang.c++, not for
comp.lang.c (even though it does involve both languages. The C+
standard defines features for interfacing to C, but C doesn''t define
any features for interfacing to C++. Furthermore, C says nothing
about C++-style exceptions.

I suspect that exception propagation across C code is system-specific,
but the folks in comp.lang.c++ can probably give you more information
on that point.

--
Keith Thompson (The_Other_Keith) ks***@mib.org <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"


On 2008-06-13 15:07, ben mitch wrote:

Hi

I hope you''ll see this cross-post (c/c++) as appropriate. I also admit
immediately that the question *may* turn out to be
compiler-/os-specific, in which case I apologize. But I wonder if
there''s an underlying truth.

We are writing a (cross-platform) ''framework'' application (in C++, as it
happens) that allows users to author ''plugins'' (as shared library
modules).

If you want it to truly be cross-platform you can not allow exceptions
to pass through to/from the plugins. The reason is simple: there is no
standardised way of doing this. The only (?) standardised calling
convention which will be available on multiple platforms is the C
calling convention and it does not support exceptions.

--
Erik Wikstr??m


这篇关于模块/语言边界上的异常传播的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆