LinuxForum.Fans
Тема

Fmemopen in Qt

Автор: Peter 12 сообщений 2391 просмотров
#205654

Здравствуйте!

Я обнаружил, что fmemopen() не работает в программе на Qt. Без Qt в тестовой консольной
работает при компиляции как gcc, так и g++, а при запуске программы на Qt при попытке
открыть файл errno устанавливается в одной программе в 11 - Resource temporarily unavailable,
в другой в 115 - Operation now in progress.

В чём тут причина? Qt настолько самостоятельна, что сама управляет памятью, не давая
делать это системе?

Пётр.

#205712

Вроде не должно быть проблем. Вот так работает:

#include <QtCore/QCoreApplication>
#include <stdio.h>

static char buffer[] = "foobar";
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
int ch;
FILE *stream;
stream = fmemopen (buffer, strlen (buffer), "r");
while ((ch = fgetc (stream)) != EOF)
printf ("Got %c\n", ch);
fclose (stream);
return a.exec();
}
#205734

Дело в том, что у меня другая ситуация - есть массив типа QByteArray с неким объектом, картинкой в формате jpg
и мне надо передать два объекта типа FILE* в подпрограмму, которая из jpg делает bmp. Для этого я djpeg
из jpegsrc.v8c.tar.gz переделал в процедуру в двух вариантах, в одном надо передавать имена файлов, в другом
FILE*, для этого я и попытался использовать fmemopen.

В тестовой программе это работает без замечаний, а в программе на Qt указатели на файлы возвращаются,
но с ранее приведёнными сообщениями и в результате не работает.

Пётр.

#205999

Peter, можно код с [не] рабочим примером? почему-то мне всегда было очень сложно уловить ход ваших мыслей...

#206030
Fat-Zer написал:
Peter, можно код с [не] рабочим примером? почему-то мне всегда было очень сложно уловить ход ваших мыслей...

С этого компьютера мне физически неудобно это делать и даже вообще набирать текст,
но там просто вызывается fmemopen, которой передаётся указатель на байт в массиве типа QByteArray
через функцию data() и смещение и при этом возникает ошибка 115, а потом ещё какая-то жалоба
на доступ к виртуальной памяти, но это позже.

Сегодня оказалось нечто ещё худшее - я попробовал другой вариант подпрограммы, которой передаются
имена файлов на диске. Предполагалось, что файлы будут для ускорения работы размещаться на электронном
диске. Однако функция open() вызывает ту же ошибку - 115, при открытии как существующего, так и нового,
для вывода. Это при использовании как электронного диска, так и физического. jpg-файл после этого на диск
мною записывается, вроде бы правильный, судя по его началу. Я при этом пользуюсь функциями C - open и write.
Но подпрограмма, которой передаются имена существующего jpg-файла и имя bmp-файла, который она должна
сама открыть и записать, создаёт bmp-файл нулевой длины и без всяких жалоб. При его открытии функцией open
та же ошибка - 115.

В чём причина такой нелюбви Qt-4.7 к функциям C, я не знаю, попробую использовать QFile. Все равно ведь его
функции в конечном счёте используют системные. В другой программе на Qt-3 с ними прблем не было.

Пётр.

#206041

Вот вам и QByteArray и даже GUI окно прикрутил на всякий случай. - работает


#include <QtGui/QApplication>
#include <QtGui/QMainWindow>
#include <QDebug>

static char buffer[] = "foobar";
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QMainWindow *dlg = new QMainWindow;
int ch;
QByteArray *test = new QByteArray(buffer,strlen(buffer));
FILE *stream;
stream = fmemopen (test->data(), strlen(buffer), "r");
while ((ch = fgetc (stream)) != EOF)
{
qDebug() << (char)ch;
}
fclose (stream);
dlg->show();
return a.exec();
}

Так что если хотите помощи - сделайте минимальный исходник который у вас не будет работать как надо и покажите.

#206066

Благодарю за проявленный интерес, но проблема где-то глубже. Ведь вариант без fmemopen тоже не работает,
как я сказал выше. В обоих вариантах для приёма bmp заводится массив размером 8MB, а всего их создаётся 4,
т.к. в программе 4 потока, выполняющих одинаковые операции. Вообще программа не моя, я её сейчас изменяю.
Почему это влияет на open() и влияет ли, я не знаю. М.б., надо в pro-файле указать дополнительные опции.
Ещё иногда бывает сообщение "Bogus virtual array access", в варианте с fmemopen оно точно бывает.

Пётр.

#206100

Peter, а не думали глубже покопаться в libjpeg и избавиться от этих костылей с файлом проецированным в память? а то выглядит оно не лучшим образом... или там никак?

#206116
Fat-Zer написал:
Peter, а не думали глубже покопаться в libjpeg и избавиться от этих костылей с файлом проецированным в память? а то выглядит оно не лучшим образом... или там никак?

Вы совершенно правы, я действительно имею намерение это сделать и изменить код этой подпрограммы и других так,
чтобы она принимала как параметры массивы и дальше чтение происходило из него, а не из файла. Я уже просматривал
её исходный текст на это предмет, затруднение в том, что надо сохранить и старый вариант, а для этого очень много
подпрограмм надо продублировать с новыми именами. Либо вводить дополнительный параметр, тогда тоже надо вводить
его везде. Наверное, проще будет сделать отдельный вариант libjpeg с чтением только из буфера.
Однако проецирование файла в память - это не костыль, это использует и ядро Linux.

Сейчас же эта преобразованная мной подпрограмма из libjpeg работает в проверочной программе, оба варианта,
но ни один не работает в рабочей программе на Qt - не записывает в файл bmp, который она должна получить из jpg,
на диске, например, создаёт файл нулевой длины, хотя jpg-файл, имя которого ей передаётся, нормальный и при вызове
из проверочной программы она его обрабатывает правильно. Кроме того, в программе на Qt при этом возникают всякие
сбои - иногда сообщения от этой подпрограммы, что jpg-файл повреждённый, иногда "Bogus virtual array access",
иногда Segmentation fault.

Пётр.

#206118
Peter написал:
[quote=Fat-Zer]Peter, а не думали глубже покопаться в libjpeg и избавиться от этих костылей с файлом проецированным в память? а то выглядит оно не лучшим образом... или там никак?

Вы совершенно правы, я действительно имею намерение это сделать и изменить код этой подпрограммы и других так,
чтобы она принимала как параметры массивы и дальше чтение происходило из него, а не из файла. Я уже просматривал
её исходный текст на это предмет, затруднение в том, что надо сохранить и старый вариант, а для этого очень много
подпрограмм надо продублировать с новыми именами. Либо вводить дополнительный параметр, тогда тоже надо вводить
его везде. Наверное, проще будет сделать отдельный вариант libjpeg с чтением только из буфера.
Однако проецирование файла в память - это не костыль, это использует и ядро Linux.

Сейчас же эта преобразованная мной подпрограмма из libjpeg работает в проверочной программе, оба варианта,
но ни один не работает в рабочей программе на Qt - не записывает в файл bmp, который она должна получить из jpg,
на диске, например, создаёт файл нулевой длины, хотя jpg-файл, имя которого ей передаётся, нормальный и при вызове
из проверочной программы она его обрабатывает правильно. Кроме того, в программе на Qt при этом возникают всякие
сбои - иногда сообщения от этой подпрограммы, что jpg-файл повреждённый, иногда "Bogus virtual array access",
иногда Segmentation fault.

Во всяком случае, это не из-за open и read/write, с QFile то же самое.

Пётр.[/quote]

#206120

Т.е. у вас две программы (одна с использованием Qt другая без использования)?
Вы вставляете какой то общий код и этот код не работает?

Все же, мне кажется, стоит забыть про Qt/не Qt. Разница в коде и/или ключах компиляции.

#206228

Проверочная программа ничего не делает, только считывает файл с jpg и вызывает
в цикле подпрограмму из libjpeg, которую я получил из djpeg. При этом никаких сообщений.
В программе на Qt она тоже вызыается постоянно, но для проверки я сделал так, что в каждом
потоке она вызывается только один раз и результаты постоянно разные. Ошибка 115 при окрытии
файлов есть всегда, bmp эта процедура не возвращает никогда, только создаёт пустой файл для
него, т.е. открывает, а другие сообщения меняются. Чаще других "Bogus virtual array accees", один
раз было "Bogus DQT 15 index4", иногда бывает Segmentation fault, иногда какие-то нарушения
доступа к сегментам памяти, при этом на экран выдаётся масса отладочной информации с адресами.

Я предполагаю, что причина в плохом качестве кода libjpeg. Ещё когда я начал его смотреть,
я обнаружил, что для доступа к переменным там используется очень грубый приём. Есть структура,
назовём её S1, существующая все время жизни djpeg, это консольная утилита для декомпрессии jpg.
Есть описание другой структуры, пусть S2, её 1-й элемент - структура S1, а за ней несколько переменных.
В одном из c-файлов вводится тип pS2 - указатель на тип S2. Затем в подпрограмме объявлен этот указатель, ps2, причём с автоматическим размещением. У этой подпрограммы есть параметр ps3 - указатель на структуры S3, содержащую указатель ps1 на S1. Автору надо что-то изменить в S1 и в элементах переменной типа S2, которой ещё нет. Он присваивает ps2 ps1 с приведением
типа: ps2=(S2 *)ps3->ps1. Затем через S1, содержащуюся в S2, меняет значения элементов S1 и устанавливает значения элементов S2. Но ведь реального отведения памяти под S2 при этом не происходит, т.е. это элементы S2 оказываются в участке памяти, которая ни подо что не распределена. При этом ничто ведь не мешает обращаться к S1 непосредственно через ps3->ps1.

Затем, после выхода из подпрограммы, когда в следующий раз требуется получить доступ к той же S1 и к другим элементам S2, он делает ту же операцию с приведением типов указателей. Для S1 это ещё приемлемо, хотя и грязно, а для эстальных элементов S2 совершенно не гарантировано, что они останутся целы до следующего к ним.

М.б., я что-то упустил, но идея именно такая. Я это частично исправил, но, видимо, не полностью и этот приём там используется во многих местах, хотя и не везде с такой ошибкой.

Также, когда я на своём компьютере из configure.ac заново построил aclocal.m4 и configure, то у меня скомпилировалась только библиотеки, а консольные утилиты - нет. При этим autoconf предложила мне запустить autoupdate для исправления устаревших макросов в configure.ac, но autoupdqte этого сдлеать не смогла и на каком-то шаге сбилась с жалобой, что в строке 295 временного файла найнед признак конца файла, хотя он продолжается и дальше. Правда, можно работать и с исходной configure, но приходится вручную корректировать версию libtool в скрипте libtool, который появляется после отработки configure.

Пётр.

Войдите или зарегистрируйтесь, чтобы ответить.