[英]What's a good, threadsafe, way to pass error strings back from a C shared library
I'm writing a C shared library for internal use (I'll be dlopen()'ing it to a c++ application, if that matters). 我正在编写一个供内部使用的C共享库(如果这很重要的话,我会将它dlopen()用于c ++应用程序)。 The shared library loads (amongst other things) some java code through a JNI module, which means all manners of nightmare error modes can come out of the JVM that I need to handle intelligently in the application.
共享库通过JNI模块加载(除此之外)一些Java代码,这意味着所有恶梦错误模式的方式都可以来自我需要在应用程序中智能处理的JVM。 Additionally, this library needs to be re-entrant.
此外,该库需要重入。 Is there in idiom for passing error strings back in this case, or am I stuck mapping errors to integers and using printfs to debug things?
在这种情况下,是否存在用于传递错误字符串的习惯用法,或者我是否将映射错误粘贴到整数并使用printfs进行调试?
Thanks! 谢谢!
My approach to the problem would be a little different from everyone else's. 我对这个问题的解决方法与其他人的方法略有不同。 They're not wrong, it's just that I've had to wrestle with a different aspect of this problem.
他们没有错,只是我不得不在这个问题的另一个方面进行斗争。
errno.h
codes demonstrate a good categorization of errors; errno.h
代码表明错误的良好分类; in fact, if you can reuse those codes (or just pass them along, eg if all your errors come ultimately from system calls), do so. errno
itself. errno
本身。 If possible, return error codes directly from functions that can fail. GetLastError()
method on your state object. GetLastError()
方法。 You have a state object, yes? errno.h
codes don't cut it), provide a function analogous to strerror
, that converts these codes to human-readable strings. errno.h
代码不会删除它),请提供类似于strerror
的函数,它将这些代码转换为人类可读的字符串。
errno
value observed immediately after the system call that failed, the name of the file involved (if any), and ideally also the name of the system call itself. errno
值的方法,即所涉及文件的名称(如果有的话) ),理想情况下也是系统调用自身的名称。 People get this wrong waaay too often -- for instance, SQLite, otherwise a well designed API, does not expose the errno
value or the name of the file, which makes it infuriatingly hard to distinguish "the file permissions on the database are wrong" from "you have a bug in your code". errno
值或文件的名称,这使得很难区分“数据库上的文件权限是错误的”从“你的代码中有一个错误”。 EDIT: Addendum: common mistakes in this area include: 编辑:附录:该领域的常见错误包括:
Also, think very carefully about which APIs ought to be allowed to fail. 另外,请仔细考虑应该允许哪些API失败。 Here are some things that should never fail:
以下是一些永远不会失败的事情:
close
and munmap
should not be able to fail. Thankfully, at least _exit
can't.) close
和munmap
不应该失败。谢天谢地,至少_exit
不能。) abort
if malloc
fails rather than trying to propagate it to your caller. malloc
失败而不是尝试将其传播给调用者,则应该立即调用abort
。 (This is not true in C++ thanks to exceptions and RAII -- if you are so lucky as to be working on a C++ project that uses both of those properly.) In closing: for an example of how to do just about everything wrong , look no further than XPCOM . 最后:关于如何解决所有错误的例子,请看XPCOM 。
You return pointers to static const char []
objects. 您返回指向
static const char []
对象的指针。 This is always the correct way to handle error strings. 这始终是处理错误字符串的正确方法。 If you need them localized, you return pointers to read-only memory-mapped localization strings.
如果需要将它们本地化,则返回指向只读内存映射本地化字符串的指针。
In C, if you don't have internationalization (I18N) or localization (L10N) to worry about, then pointers to constant data is a good way to supply error message strings. 在C中,如果您不需要担心国际化(I18N)或本地化(L10N),那么指向常量数据的指针是提供错误消息字符串的好方法。 However, you often find that the error messages need some supporting information (such as the name of the file that could not be opened), which cannot really be handled by constant data.
但是,您经常发现错误消息需要一些支持信息(例如无法打开的文件的名称),这些信息实际上不能由常量数据处理。
With I18N/L10N to worry about, I'd recommend storing the fixed message strings for each language in an appropriately formatted file, and then using mmap()
to 'read' the file into memory before you fork any threads. 考虑到I18N / L10N,我建议将每种语言的固定消息字符串存储在适当格式的文件中,然后在分叉任何线程之前使用
mmap()
将文件“读取”到内存中。 The area so mapped should then be treated as read-only (use PROT_READ
in the call to mmap()
). 这样映射的区域应该被视为只读(在调用
mmap()
使用PROT_READ
)。
This avoids complicated issues of memory management and avoids memory leaks. 这避免了复杂的内存管理问题并避免了内存泄漏。
Consider whether to provide a function that can be called to get the latest error. 考虑是否提供可以调用以获取最新错误的函数。 It can have a prototype such as:
它可以有一个原型,如:
int get_error(int errnum, char *buffer, size_t buflen);
I'm assuming that the error number is returned by some other function call; 我假设其他函数调用返回错误号; the library function then consults any threadsafe memory it has about the current thread and the last error condition returned to that thread, and formats an appropriate error message (possibly truncated) into the given buffer.
库函数然后查询它有关当前线程的任何线程安全内存以及返回到该线程的最后一个错误条件,并将适当的错误消息(可能被截断)格式化为给定的缓冲区。
With C++, you can return (a reference to) a standard String from the error reporting mechanism; 使用C ++,您可以从错误报告机制返回(引用)标准字符串; this means you can format the string to include the file name or other dynamic attributes.
这意味着您可以格式化字符串以包含文件名或其他动态属性。 The code that collects the information will be responsible for releasing the string, which isn't (shouldn't be) a problem because of the destructors that C++ has.
收集信息的代码将负责释放字符串,由于C ++具有析构函数,因此不会(不应该)成为问题。 You might still want to use
mmap()
to load the format strings for the messags. 您可能仍希望使用
mmap()
来加载messag的格式字符串。
You do need to be careful about the files you load and, in particular, any strings used as format strings. 您需要注意加载的文件,特别是用作格式字符串的任何字符串。 (Also, if you are dealing with I18N/L10N, you need to worry about whether to use the '
n$
notation to allow for argument reordering; and you have to worry about different rules for different cultures/languages about the order in which the words of a sentence are presented.) (此外,如果您正在处理I18N / L10N,您需要担心是否使用'
n$
表示法来允许参数重新排序;并且您必须担心不同文化/语言的不同规则有关提出一个句子的单词。)
I guess you could use PWideChars, as Windows does. 我想你可以像Windows一样使用PWideChars。 Its thread safe.
它的线程安全。 What you need is that the calling app creates a PwideChar that the Dll will use to set an error.
你需要的是调用应用程序创建一个PllChar,Dll将用它来设置错误。 Then, the callling app needs to read that PWideChar and free its memory.
然后,callling app需要读取该PWideChar并释放其内存。
R. has a good answer (use static const char []), but if you are going to have various spoken languages, I like to use an Enum to define the error codes. R.有一个很好的答案(使用static const char []),但是如果你要使用各种口语,我喜欢使用Enum来定义错误代码。 That is better than some #define of a bunch of names to an int value.
这比一些名称中的某些#define要好一个int值。
errno
— even if it is potentially TLSed by an implementation); errno
- 即使它可能被实现TLS); aking to Linux kernel's style of return -ENOENT;
return -ENOENT;
风格return -ENOENT;
. strerror
that takes such an integer and returns a pointer to a const string. strerror
的函数,它接受一个这样的整数并返回一个指向const字符串的指针。 This function can transparently do I18N if needed, too, as gettext-returnable strings also remain constant over the lifetime of the translation database. If you need to provide non-static error messages, then I recommend returning strings like this: error_code_t function(, char** err_msg). 如果您需要提供非静态错误消息,那么我建议返回如下字符串:error_code_t function(,char ** err_msg)。 Then provide a function to free the error message: void free_error_message(char* err_msg).
然后提供一个释放错误消息的函数:void free_error_message(char * err_msg)。 This way you hide how the error strings are allocated and freed.
这样,您可以隐藏错误字符串的分配和释放方式。 This is of course only worth implementing of your error strings are dynamic in nature, meaning that they convey more than just a translation of error codes.
这当然只值得实现您的错误字符串本质上是动态的,这意味着它们传达的不仅仅是错误代码的转换。
Please havy oversight with mu formatting. 请用mu格式来监督疏忽。 I'm writing this on a cell phone...
我在手机上写这个...
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.