我正在尝试从使用fmemopen
char *
创建的流中读取一个宽字符。
char *s = "foo bar foo";
FILE *f = fmemopen(s,strlen(s),"r");
wchar_t c = getwc(f);
getwc
抛出了分段错误,我使用GDB进行了检查。
我知道这是因为打开了fmemopen
的流,因为在打开的流上调用getwc
通常正常。
是否存在fmemopen
的宽字符版本,还是有其他方法可以解决此问题?
答案 0 :(得分:7)
第二行应为FILE *f = fmemopen(s, strlen(s), "r");
。发布后,fmemopen
有未定义的行为,可能会返回NULL
,导致getwc()
崩溃。
更改fmemopen()
行并添加NULL
检查可修复崩溃,但不符合OP目标。
对于使用fmemopen()
打开的流,似乎不支持广泛的方向,至少对于GNU C库而言。请注意,fmemopen
未在C标准中定义,而是在POSIX.1-2008中定义,并且在许多系统(如OS / X)上不可用。
以下是您的计划的更正和扩展版本:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
int main(void) {
const char *s = "foo bar foo";
FILE *f = fmemopen((void *)s, strlen(s), "r");
wchar_t c;
if (f == NULL) {
printf("fmemopen failed: %s\n", strerror(errno));
return 1;
}
printf("default wide orientation: %d\n", fwide(f, 0));
printf("selected wide orientation: %d\n", fwide(f, 1));
while ((c = getwc(f)) != WEOF) {
printf("read %lc (%d 0x%x)\n", c, c, c);
}
return 0;
}
在linux上运行:
default wide orientation: -1
selected wide orientation: -1
没有输出,立即返回WEOF
。
来自linux手册页的fwide(f, 0)
的解释:
概要
#include <wchar.h> int fwide(FILE *stream, int mode);
当
mode
为零时,fwide()
函数会确定stream
的当前方向。如果stream
是面向宽字符的,即,如果允许宽字符I / O但不允许char I / O,则返回正值。如果stream
是面向字节的,则返回负值,即,如果允许char I / O但不允许宽字符I / O.如果stream
尚无方向,则返回零;在这种情况下,下一个I / O操作可能会改变方向(如果是char I / O操作,则改为字节,如果是宽字符I / O操作,则改为宽字符)。一旦流具有方向,它就无法更改并持续直到关闭流。
当
mode
非零时,fwide()
函数首先尝试设置stream
的方向(如果模式大于0,则为宽字符方向,或者为字节如果mode
小于0,则导向。然后它返回一个表示当前方向的值,如上所述。
fmemopen()
返回的流是面向字节的,不能更改为面向广角的。
答案 1 :(得分:3)
您的第二行没有使用正确数量的参数,是吗?已更正
FILE *fmemopen(void *buf, size_t size, const char *mode);
glibc的fmemopen
没有(完全)支持宽字符AFAIK。还有open_wmemstream()
,它支持广泛的字符,但仅用于写作。
是否定义了_UNICODE
?见wchar_t reading。
同样,您是否将语言环境设置为支持Unicode的编码,例如setlocale(LC_ALL, "en_US.UTF-8");
?见here。
我已经更改了我的代码并采用了@chqrlie中的代码,因为它更接近OP代码但添加了语言环境,否则无法为扩展/ Unicode字符生成正确的输出。
#include <errno.h>
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <stdlib.h>
#include <locale.h>
int main(void)
{
setlocale(LC_ALL, "en_US.UTF-8");
const char *s = "foo $€ bar foo";
FILE *f = fmemopen((void *)s, strlen(s), "r");
wchar_t c;
if (f == NULL) {
printf("fmemopen failed: %s\n", strerror(errno));
return 1;
}
printf("default wide orientation: %d\n", fwide(f, 0));
printf("selected wide orientation: %d\n", fwide(f, 1));
while ((c = getwc(f)) != WEOF) {
printf("read %lc (%d 0x%x)\n", c, c, c);
}
return 0;
}
答案 2 :(得分:1)
您只能在无定向或面向广播的流上使用getwc()
。来自getwc()
https://link.springer.com/article/10.1007/s10032-011-0175-3:该流不具有方向,或者是广泛的。
如果流已经有方向,则无法更改流方向。来自fwide()
man page:在已经有方向的流上调用此函数无法更改它。
使用glibc打开的流fmemopen()
具有字节方向,因此无法以任何方式进行广泛定向。如上所述,man page here具有fmemopen()
例程,没有此限制。
结论:您需要使用uClibc或其他图书馆或制作自己的fmemopen()
。