I was testing the interaction of fseek and fgetpos (more precisely if I can get an fpos_t that's inside a multi byte) and got into a pretty unexpected situation.
Whenever I use setlocale(LC_CTYPE, "C.UTF-8");
and fputwc
, fseek
seems to not work anymore and the only way to move the cursor inside the file is to use fgetwc
.
The code is below (all calls complete successfully, i.e. setlocale, fseek, fputwc, etc.., for brevity I stripped the checking of the return value).
This happens on Ubuntu with glibc 2.16. Does anyone have a good explanation why this happens? Is this a bug in glibc?
setlocale(LC_CTYPE, "C.UTF-8");
uselocale(LC_GLOBAL_LOCALE);
FILE* fp = fopen("/tmp/wc.test", "w+");
wchar_t wc = 0x00a2;
fputwc(wc, fp);
fflush(fp);
rewind(fp);
long ftell_out;
fpos_t fpos_out;
fseek(fp, 1, SEEK_SET); // looks like it doesn't have any effect
ftell_out = ftell(fp); // ftell_out is 0
fgetpos(fp, &fpos_out); // the (inner) offset of fpos_out is 0 as well
fgetwc(fp); // it reads wc(0x00a2) here as if we are at
ftell_out = ftell(fp); // this is 2
fgetpos(fp, &fpos_out); // this is 2
Some notes:
if I close the file and reopen it in read more then everything works as expected (after
fseek
,ftell_out
/fpos_out
are1
andfgetwc
fails with a propererrno
since the position is inside a multibyte)if I don't use
setlocale
the output is almost as expected except thatfgetwc
doesn't set theerrno
anymore.