LINUX.ORG.RU

Сообщения Gyros

 

Слетает выравнивание для строк с русскими символами. Unicode в Си.

Всех приветствую!

Все таки решил создать новую тему.

Хотя обсуждение началось в этой теме, но там оно больше уклонилось в лингвистическую строну, да и у меня немного другой вопрос.

Проблема вот в чем: если в printf-е мы ставим «%30s», то у нас выводится сначало 30-length(str) пробелов, потом наша строка str длиной length(str).

Но это не работает, если в строке есть не англ. символы.

Чтобы проверить какое будет поведение под Windows и Linux, а также с char* и wchar_t*, набросал программку:



#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#include <locale.h>
#include <wchar.h>
#include <uchar.h> // for char16_t


char *str_dup(char const *in)
{
    size_t len = strlen(in);
    char *out = malloc(len+1);
    strncpy(out, in, len+1);
    return out;
}

wchar_t *wstr_dup(wchar_t const *in)
{
    size_t len = wcslen(in);
    wchar_t *out = malloc((len+1)* sizeof(wchar_t));
    wcsncpy(out, in, (len+1) );
    return out;
}

wchar_t* convert_to_wstr(const char* cstr)
{
    mbstate_t state;
    memset(&state, 0, sizeof(state) );
    size_t out_sz = 1 + mbsrtowcs(NULL, &cstr, 0, &state);
    
    wchar_t* ws = malloc(out_sz*sizeof(wchar_t) );
    mbstowcs(ws, cstr, out_sz);
    return ws;
}

char* convert_to_cstr(const wchar_t* wstr)
{
    mbstate_t state;
    memset(&state, 0, sizeof(state) );
    size_t out_sz = 1 + wcsrtombs(NULL, &wstr, 0, &state);
    
    char* cs = malloc(out_sz*sizeof(char) );
    wcstombs(cs, wstr, out_sz);
    return cs;
}

/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
typedef struct CSTRUCT
{
	char* data_only_engl; // только англ. буквы
        char* data_from_file; // строка из файла
        char* data_from_prog; // строка в программе
} CSTRUCT;

CSTRUCT* cs_create(const char* cstr)
{
	CSTRUCT* cs = malloc(sizeof(CSTRUCT));

	cs->data_only_engl = str_dup("Hello Friend");
	cs->data_from_prog = str_dup(cstr);

	FILE *input = fopen("text.txt", "r");
    char buff[128];
    memset(buff, '\0', 128);
    fgets(buff, 128, input);
    	cs->data_from_file = str_dup(buff);
	return cs;
}

void cs_print(CSTRUCT* cs)
{
	fprintf(stdout,"------------------------------|\n");
	const char FMT[] = "%30s| %2ld\n";
	fprintf(stdout, FMT, cs->data_only_engl, strlen(cs->data_only_engl) );
	fprintf(stdout, FMT, cs->data_from_prog, strlen(cs->data_from_prog) );
	fprintf(stdout, FMT, cs->data_from_file, strlen(cs->data_from_file) );
	fprintf(stdout,"123456789012345678901234567890|\n"); // ровно 30 символов
}

void cs_free(CSTRUCT** cs)
{
	free( (*cs)->data_from_prog);
	free( (*cs)->data_from_file);
	free( (*cs)->data_only_engl);
	free(*cs);
}
/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/



typedef struct WSTRUCT
{
	wchar_t* data_only_engl;
        wchar_t* data_from_file;
        wchar_t* data_from_prog;
} WSTRUCT;


WSTRUCT* ws_create(const char* str)
{
	WSTRUCT* ws = malloc(sizeof(WSTRUCT));
	ws->data_only_engl = wstr_dup(L"Hello Friend");
	ws->data_from_prog = convert_to_wstr(str);

	FILE *input = fopen("text.txt", "r");
    char buff[128];
    memset(buff, '\0', 128);
    fgets(buff, 128, input);
    
	ws->data_from_file = convert_to_wstr(buff);
	return ws;
}

void ws_print(WSTRUCT* ws)
{
	fprintf(stdout,"------------------------------|\n");
	const char FMT[] = "%30ls| %2ld\n";
	fprintf(stdout, FMT, ws->data_only_engl, wcslen(ws->data_only_engl) );
	fprintf(stdout, FMT, ws->data_from_prog, wcslen(ws->data_from_prog) );
	fprintf(stdout, FMT, ws->data_from_file, wcslen(ws->data_from_file) );
	fprintf(stdout,"123456789012345678901234567890|\n");
}

void ws_free(WSTRUCT** ws)
{
	free( (*ws)->data_from_prog);
	free( (*ws)->data_from_file);
	free( (*ws)->data_only_engl);
	free(*ws);
}



int main(int argc, char const *argv[])
{
	
#if defined (_WIN32)
	setlocale(LC_ALL, "ru_RU");
#else
	setlocale(LC_ALL, "ru_RU.utf8");
#endif

	printf("sizeof(char)    = %ld\n", sizeof(char) );
	printf("sizeof(char16_t)= %ld\n", sizeof(char16_t) );
	printf("sizeof(wchar_t) = %ld\n", sizeof(wchar_t) );
	printf("\n");


	CSTRUCT* cs = cs_create("Hello! Друг");
	cs_print(cs);
	cs_free(&cs);

	WSTRUCT* ws = ws_create("Hello! Друг");
	ws_print(ws);
	ws_free(&ws);


	return EXIT_SUCCESS;
}

Кратко: есть две структуры одна хранит строки в char*, другая - wchar_t*.

Обе хранят три строки: с чисто англ. символами, со строкой инициализируемой в программе и строкой считываемой из файла:

text.txt

Привет friend из файла!

В итоге под Linux получаю

sizeof(char)    = 1
sizeof(char16_t)= 2
sizeof(wchar_t) = 4

------------------------------|
                  Hello Friend| 12
               Hello! Друг| 15
Привет friend из файла!
| 37
123456789012345678901234567890|
------------------------------|
                  Hello Friend| 12
               Hello! Друг| 11
Привет friend из файла!
| 24
123456789012345678901234567890|

Видно, что выравнивание сработало для строки только с англ. символами.

А хотелось бы:

------------------------------|
                  Hello Friend| 12
                   Hello! Друг| 11
       Привет friend из файла!| 23
123456789012345678901234567890|

Соответственно под Windows имею:

sizeof(char)    = 1
sizeof(char16_t)= 2
sizeof(wchar_t) = 2

------------------------------|
                  Hello Friend| 12
               Hello! Друг| 15
Привет friend из файла!
| 37
123456789012345678901234567890|
------------------------------|
                  Hello Friend| 12
               Hello! Друг| 15
Привет friend из файла!
| 37
123456789012345678901234567890|

Как сделать кроссплатф. вывод на экран с правильным выравниваем?

 , , , ,

Gyros
()

Проблема при сборке библиотеки: ключ -fPIC

Всех приветствую!

Знает ли кто-нибудь решение такой проблемы:

собираю библиотеку (lib)xlsxio,но для нее нужна minizip-ng:

действую

cmake -S . -B build -D MZ_BUILD_TESTS=ON

~/minizip-ng$ cmake -S . -B build -D MZ_BUILD_TESTS=ON
-- Using CMake version 3.16.3
-- Using ZLIB 1.3.1
-- BZip2 library not found
-- Checking for module 'liblzma'
--   No package 'liblzma' found
-- Using LZMA 5.2.4
-- Checking for module 'libzstd'
--   No package 'libzstd' found
-- ZSTD library not found
-- Using OpenSSL 3.2.2
-- Using Iconv
-- The following features have been enabled:

 * MZ_COMPAT, Enables compatibility layer
 * MZ_ZLIB, Enables ZLIB compression
 * MZ_LZMA, Enables LZMA & XZ compression
 * MZ_PKCRYPT, Enables PKWARE traditional encryption
 * MZ_WZAES, Enables WinZIP AES encryption
 * MZ_OPENSSL, Enables OpenSSL for encryption
 * MZ_LIBBSD, Builds with libbsd crypto random
 * MZ_ICONV, Enables iconv string encoding conversion library
 * MZ_BUILD_TESTS, Builds minizip test executable

-- The following features have been disabled:

 * MZ_BZIP2, Enables BZIP2 compression
 * MZ_ZSTD, Enables ZSTD compression
 * MZ_LIBCOMP, Enables Apple compression
 * MZ_FETCH_LIBS, Enables fetching third-party libraries if not found
 * MZ_FORCE_FETCH_LIBS, Enables fetching third-party libraries always
 * MZ_COMPRESS_ONLY, Only support compression
 * MZ_DECOMPRESS_ONLY, Only support decompression
 * MZ_FILE32_API, Builds using posix 32-bit file api
 * MZ_BUILD_UNIT_TESTS, Builds minizip unit test project
 * MZ_BUILD_FUZZ_TESTS, Builds minizip fuzzer executables
 * MZ_CODE_COVERAGE, Builds with code coverage flags

-- Configuring done
-- Generating done
-- Build files have been written to: /home/bark/minizip-ng/build

Потом

cmake –build build

~/minizip-ng$ cmake --build build
make[1]: Entering directory '/home/bark/minizip-ng/build'
make[2]: Entering directory '/home/bark/minizip-ng/build'
make[2]: Leaving directory '/home/bark/minizip-ng/build'
make[2]: Entering directory '/home/bark/minizip-ng/build'
[  4%] Building C object CMakeFiles/minizip.dir/mz_crypt.c.o
[  8%] Building C object CMakeFiles/minizip.dir/mz_os.c.o
[ 13%] Building C object CMakeFiles/minizip.dir/mz_strm.c.o
[ 17%] Building C object CMakeFiles/minizip.dir/mz_strm_buf.c.o
[ 21%] Building C object CMakeFiles/minizip.dir/mz_strm_mem.c.o
[ 26%] Building C object CMakeFiles/minizip.dir/mz_strm_split.c.o
[ 30%] Building C object CMakeFiles/minizip.dir/mz_zip.c.o
[ 34%] Building C object CMakeFiles/minizip.dir/mz_zip_rw.c.o
[ 39%] Building C object CMakeFiles/minizip.dir/mz_strm_zlib.c.o
[ 43%] Building C object CMakeFiles/minizip.dir/mz_strm_lzma.c.o
[ 47%] Building C object CMakeFiles/minizip.dir/mz_crypt_openssl.c.o
[ 52%] Building C object CMakeFiles/minizip.dir/mz_os_posix.c.o
[ 56%] Building C object CMakeFiles/minizip.dir/mz_strm_os_posix.c.o
[ 60%] Building C object CMakeFiles/minizip.dir/mz_strm_pkcrypt.c.o
[ 65%] Building C object CMakeFiles/minizip.dir/mz_strm_wzaes.c.o
[ 69%] Building C object CMakeFiles/minizip.dir/compat/ioapi.c.o
[ 73%] Building C object CMakeFiles/minizip.dir/compat/unzip.c.o
[ 78%] Building C object CMakeFiles/minizip.dir/compat/zip.c.o
[ 82%] Linking C static library libminizip.a
make[2]: Leaving directory '/home/bark/minizip-ng/build'
[ 82%] Built target minizip
make[2]: Entering directory '/home/bark/minizip-ng/build'
make[2]: Leaving directory '/home/bark/minizip-ng/build'
make[2]: Entering directory '/home/bark/minizip-ng/build'
[ 86%] Building C object CMakeFiles/minizip_cli.dir/minizip.c.o
[ 91%] Linking C executable minizip
make[2]: Leaving directory '/home/bark/minizip-ng/build'
[ 91%] Built target minizip_cli
make[2]: Entering directory '/home/bark/minizip-ng/build'
make[2]: Leaving directory '/home/bark/minizip-ng/build'
make[2]: Entering directory '/home/bark/minizip-ng/build'
[ 95%] Building C object CMakeFiles/minigzip_cli.dir/minigzip.c.o
[100%] Linking C executable minigzip
make[2]: Leaving directory '/home/bark/minizip-ng/build'
[100%] Built target minigzip_cli
make[1]: Leaving directory '/home/bark/minizip-ng/build'

Потом устанавливаю в usr/local sudo make install

Теперь собираю xlsxio:


~/xlsxio$ cmake -G"Unix Makefiles"
CMake Warning:
  No source or binary directory provided.  Both will be assumed to be the
  same as the current working directory, but note that this warning will
  become a fatal error in future CMake releases.


-- XLSX I/O library version: 0.2.35
-- Configuring done
-- Generating done
-- Build files have been written to: /home/bark/xlsxio
bark@zuzu:~/xlsxio$ make
make[1]: Entering directory '/home/bark/xlsxio'
make[2]: Entering directory '/home/bark/xlsxio'
make[2]: Leaving directory '/home/bark/xlsxio'
make[2]: Entering directory '/home/bark/xlsxio'
[  4%] Building C object CMakeFiles/xlsxio_read_SHARED.dir/lib/xlsxio_read.c.o
[  8%] Building C object CMakeFiles/xlsxio_read_SHARED.dir/lib/xlsxio_read_sharedstrings.c.o
[ 13%] Linking C shared library libxlsxio_read.so
/usr/bin/ld: /usr/local/lib/libminizip.a(mz_strm.c.o): relocation R_X86_64_PC32 against symbol `mz_stream_write' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: bad value
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/xlsxio_read_SHARED.dir/build.make:102: libxlsxio_read.so] Error 1
make[2]: Leaving directory '/home/bark/xlsxio'
make[1]: *** [CMakeFiles/Makefile2:150: CMakeFiles/xlsxio_read_SHARED.dir/all] Error 2
make[1]: Leaving directory '/home/bark/xlsxio'
make: *** [Makefile:130: all] Error 2

Проблема тут

relocation R_X86_64_PC32 against symbol `mz_stream_write’ can not be used when making a shared object; recompile with -fPIC

Тогда ставлю в minizip-ng/CMakeLists.txt

на СЛЕДУЮЩЕЙ строке после комментария

# Set compiler options

строчку SET(CMAKE_SHARED_LIBRARY_C_FLAGS «-fpic»)

Потом, пересобираю, устанавливаю minixip-ng

Возвращаюсь к xlsxio:

результат такой же, тот же выхлоп в консоль, опять не может прилинковать

[ 13%] Linking C shared library libxlsxio_read.so

Linking C shared library libxlsxio_read.so
/usr/bin/ld: /usr/local/lib/libminizip.a(mz_strm.c.o): relocation R_X86_64_PC32 against symbol `mz_stream_write' can not be used when making a shared object; recompile with -fPIC
/usr/bin/ld: final link failed: bad value

Пока не ясно в чем проблема.

Странно, что разработчики в соих инструкциях по сборке никак момент с -fPIC не упомянули.

Видимо это считается тривиальным моментом..

 , ,

Gyros
()

Сборка Freetype-GL в Windows для mingw и символические ссылки на файлы

Всех приветствую!

Хочу описать процесс сборки указанной выше библиотеки и задать вопрос. Сразу вопрос может показаться непонятным.

Итак, сборка:

  1. Имеем установленный MSYS (C:\msys64\ucrt64) плюс минимально необх. библиотеки
pacman -S mingw-w64-ucrt-x86_64-gcc
pacman -S mingw-w64-ucrt-x86_64-cmake
pacman -S mingw-w64-ucrt-x86_64-make
pacman -S mingw-w64-ucrt-x86_64-glew
pacman -S mingw-w64-ucrt-x86_64-glfw
pacman -S mingw-w64-ucrt-x86_64-fontconfig
pacman -S mingw-w64-ucrt-x86_64-freetype
pacman -S mingw-w64-ucrt-x86_64-harfbuzz
pacman -S mingw-w64-ucrt-x86_64-pkg-config
pacman -S mingw-w64-ucrt-x86_64-doxygen

установленные через шелл msys2.exe

  1. скачиваем Freetype GL https://github.com/rougier/freetype-gl/tree/master в C:\freetype-gl

  2. Читаем в INSTALL.md

 **Note**: Harfbuzz examples only work with symbolic links enabled. See <https://github.com/git-for-windows/git/wiki/Symbolic-links>

Поэтому делаем для всех файлов (кроме texture-font.h, texture-font.с, freetype-gl-err.h, freetype-gl-err.c ) в папке C:\freetype-gl\harfbuzz символические ссылки на файлы с теми же именами, но на уровень каталога выше.

(

По умолчанию создание символич. ссылок в Windows не разрешено.

Для этого включаем разрешение на создание символич. ссылок в Windows (в моем случае Windows 11).

Чтобы включить разрешение нужно запустить оснастку Group Policy Editor: Win+R gpedit.msc Конфигурация компьютера->Конфигурация Windows->Параметры безопасности->Локальные политики->Назначение прав пользователя добавляем своего user-а в пункте «Создание символических ссылок».

PS. Если такой оснастки нет, то устанавливаем ее: запускаем терминал с правами администратор и вводим: сначала

FOR %F IN ("%SystemRoot%\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientTools-Package~*.mum") DO ( DISM /Online /NoRestart /Add-Package:"%F" ) 

потом

FOR %F IN ("%SystemRoot%\servicing\Packages\Microsoft-Windows-GroupPolicy-ClientExtensions-Package~*.mum") DO ( DISM /Online /NoRestart /Add-Package:"%F" )

)

Создание ссылок происходит так:

Запоминаем имя файла находящегося в C:\freetype-gl\harfbuzz, удаляем его из папки. Потом в этом каталоге выполняем

mklink <имя файла>  C:\freetype-gl\<имя файла>

Например,

mklink  freetype-gl-errdef.h C:\freetype-gl\freetype-gl-errdef.h

будет выдано

symbolic link created for freetype-gl-errdef.h <<===>> C:\freetype-gl\freetype-gl-errdef.h

Вот здесь вопрос(!?): а то делать с файлами freetype-gl-err.h, freetype-gl-err.c у которых нет в папке C:\freetype-gl аналогов с такими же именами?

Например, файл freetype-gl-err.h содержит одну строку «../freetype-gl-err.h», но уровнем выше нет файла с таким именем.

Т.е. нам нужно переделать файл в ссылку, но как будто не существует файла на который он должен ссылатся.

Это относится к этим двум файлам.

Естественно из-за этого сборка будет неудачной.

В репозитории Freetype GL в описании комита на эти файлы указано «Add harfbuzz support for errno stuff».

mkdir C:\freetype-gl\build

далее запускаем шелл C:\msys64\urct64.exe и в нем выполняем

  cd C:\freetype-gl\build

Далее возможны два варианта (все команды вып. в шелле C:\msys64\urct64.exe):

3а)

cmake -G "MinGW Makefiles"  -Dfreetype-gl_BUILD_HARFBUZZ=ON ..

потом mingw32-make

Отваливается в самом начале на:

[ 26%] Building C object harfbuzz/CMakeFiles/freetype-gl-hb.dir/platform.c.obj
[ 27%] Building C object harfbuzz/CMakeFiles/freetype-gl-hb.dir/texture-atlas.c.obj
[ 28%] Building C object harfbuzz/CMakeFiles/freetype-gl-hb.dir/texture-font.c.obj
In file included from C:\freetype-gl\harfbuzz\texture-font.c:15:
C:\freetype-gl\harfbuzz\freetype-gl-err.h:1:1: error: expected identifier or '(' before '.' token
    1 | ../freetype-gl-err.h
      | ^
C:\freetype-gl\harfbuzz\texture-font.c:26:3: warning: data definition has no type or storage class
   26 | } FT_Errors[] =
      |   ^~~~~~~~~
C:\freetype-gl\harfbuzz\texture-font.c:26:3: error: type defaults to 'int' in declaration of 'FT_Errors' [-Wimplicit-int]
In file included from C:/msys64/ucrt64/include/freetype2/freetype/fterrors.h:200,
                 from C:\freetype-gl\harfbuzz\texture-font.c:27:
C:/msys64/ucrt64/include/freetype2/freetype/fterrdef.h:58:3: warning: braces around scalar initializer
   58 |   FT_NOERRORDEF_( Ok,                                        0x00,
...

3б)

cmake -G "MinGW Makefiles"  -Dfreetype-gl_BUILD_HARFBUZZ=OFF ..

потом mingw32-make

Тут компилирует почти все примеры библиотеки, отваливается на

[ 94%] Building C object demos/CMakeFiles/markup.dir/markup.c.obj
[ 96%] Linking C executable markup.exe
C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles\markup.dir/objects.a(markup.c.obj):markup.c:(.text+0x15): undefined reference to `FcInit'
C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles\markup.dir/objects.a(markup.c.obj):markup.c:(.text+0x21): undefined reference to `FcNameParse'
C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles\markup.dir/objects.a(markup.c.obj):markup.c:(.text+0x3c): undefined reference to `FcConfigSubstitute'
C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles\markup.dir/objects.a(markup.c.obj):markup.c:(.text+0x48): undefined reference to `FcDefaultSubstitute'
C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles\markup.dir/objects.a(markup.c.obj):markup.c:(.text+0x60): undefined reference to `FcFontMatch'
C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles\markup.dir/objects.a(markup.c.obj):markup.c:(.text+0x70): undefined reference to `FcPatternDestroy'
C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles\markup.dir/objects.a(markup.c.obj):markup.c:(.text+0xc5): undefined reference to `FcPatternGet'
C:/msys64/ucrt64/bin/../lib/gcc/x86_64-w64-mingw32/14.2.0/../../../../x86_64-w64-mingw32/bin/ld.exe: CMakeFiles\markup.dir/objects.a(markup.c.obj):markup.c:(.text+0x113): undefined reference to `FcPatternDestroy'
collect2.exe: error: ld returned 1 exit status
mingw32-make[2]: *** [demos\CMakeFiles\markup.dir\build.make:112: demos/markup.exe] Error 1
mingw32-make[1]: *** [CMakeFiles\Makefile2:902: demos/CMakeFiles/markup.dir/all] Error 2
mingw32-make: *** [Makefile:145: all] Error 2

Но можно сказать уже успех.

Делитесь своими мыслями по поводу описанного.

Кто как собирает с меньшими издержками?

Что делать со ссылками непонятно куда?

Заранее благодарен за содержательные комментарии.

 , , , ,

Gyros
()

Как гарантированно заNULLить указатель на уже освобожденный объект

Всех приветствую!

Может кому-нибудь мой вопрос покажется надуманным, но все равно напишу.

Есть (в данном примере игрушечный) код

KIT*   kit=NULL;

// создаем kit
kit = kit_create("Abracadabra", 5);

// пользуемся kit
// ...
kit_print(stdout, kit);
// ...

// освобождаем kit
kit_free(kit);
	
// ...	

// забыли, что уже освободили kit и делаем распечатку
kit_print(stdout, kit);
//Segmentation fault

Segmentation fault

Т.к. после

#define SAFE_FREE(object) if(object!=NULL) {free(object); (object)=NULL;}
void  kit_free(KIT *kit)
{   
	SAFE_FREE(kit->name);
	SAFE_FREE(kit->data);
	SAFE_FREE(kit);
}

указатель на kit не будет NULL на вызывающей стороне. И даже если сделать проверку в kit_print

if (kit != NULL && kit->data != NULL)
{  
  // печатаем kit
}
else
  printf("Извините, но kit=NULL");

все равно в kit_print придет ненулевой указатель.

Варианты решения:

   kit_free(kit);
   kit=NULL;

Недостаток: лишняя строка которую можно забыть написать, и вообще хотелось бы чтобы все делалось в kit_free

Сделать

KIT*  kit_free(KIT *kit)
{   
	SAFE_FREE(kit->name);
	SAFE_FREE(kit->data);
	SAFE_FREE(kit);
	return kit; // уже ставший NULL
}

и вызывать

kit = kit_free(kit);

Выглядит неплохо.

А теперь вопрос:

Имеются ли у кого-нибудь более изящные решения или возможен иной принципиально подход к освобождению памяти в pure C ?

 , , ,

Gyros
()

Глюк с инициализацией глобальных переменных (C/mingw)

Всех приветствую!

Обнаружилось непонятное явление: после компиляции mingw32 и запуска под wine в программе не инициализируются глобальные переменные.

Более подробно:

Глобальные переменные:

bool line_mode = false;
enum {ORTHOGRAPHIC=0, PERSPECTIVE};
int projection_type=ORTHOGRAPHIC;

Некоторые ф-ции:

void reshape_cb (int w, int h)
{
    glViewport ( 0, 0, (GLint) w, (GLint) h ) ;
    WIDTH = w;
    HEIGHT = h;

       
    printf("projection_type = %d\n", projection_type);
    printf("line_mode = %d\n", line_mode);
    switch ( projection_type )
    {
      case PERSPECTIVE:
        printf("PERSPECTIVE\n");
        ...        
        break;

      case ORTHOGRAPHIC:
        printf("ORTHOGRAPHIC\n");
        ...
        break;
    };

    ...
    CHECK_GL_ERROR(); 
    printf("reshape()\n");
}
void keyboard_cb ( unsigned char key, int x, int y )
{
    switch ( key )
    {
      case 'l' :
      case 'L' :
      {
          line_mode = !line_mode;
          break;
      }

      case '1' :
      {
          projection_type = ORTHOGRAPHIC;
          reshape_cb(WIDTH, HEIGHT);
          break;
      }

      case '2' :
      {
          projection_type = PERSPECTIVE;
          reshape_cb(WIDTH, HEIGHT);
          break;
      }

      ...

    };

    glutPostRedisplay();
}

После запуска wine program.exe на экран выдается

projection_type = -1122261533
line_mode = 100
reshape()

При компиляции gcc все нормально:

projection_type = 0
line_mode = 0
ORTHOGRAPHIC
reshape()

Лечится это явление добавлением static:

static bool line_mode = false;
enum {ORTHOGRAPHIC=0, PERSPECTIVE};
static int projection_type=ORTHOGRAPHIC;

(или, возможно, инициализацией в ф-ции main) Тогда правильно работает и после mingw.

Кто-нибудь сталкивался с таким явлением? Почему это происходит?

Добавление.

Если после запуска wine program.exe нажать клавишу [2], то

projection_type = -1122261533
line_mode = 100
reshape()
НАЖАТИЕ КЛАВИШИ [2]
projection_type = 1
line_mode = 100
PERSPECTIVE
reshape()

видно значение projection_type инициализировалось как и задумано.

Тоже самое после gcc: ./program

projection_type = 0
line_mode = 0
ORTHOGRAPHIC
reshape()
НАЖАТИЕ КЛАВИШИ [2]
projection_type = 1
line_mode = 0
PERSPECTIVE
reshape()

PS Заранее благодарю за осмысленные ответы.

PS2 К сожалению, сделать маленький пример на выдачу этой ошибки пока не удалось. А вываливать кучу файлов сюда неуместно. Могу exe-шник дать для анализа явления.

 , , , ,

Gyros
()

Как обойти/исправить ошибку при сборке библиотек mxe?

Всех приветствую! Пытаюсь собрать некоторые библиотеки для mxe. На каком-то этапе происходит ошибка:


[download]    libsndfile-1.1.0.tar.xz
[build]       libsndfile              x86_64-w64-mingw32.static

Failed to build package libsndfile for target x86_64-w64-mingw32.static!
------------------------------------------------------------
configure.ac:345: the top level
autom4te: error: /usr/bin/m4 failed with exit status: 1
aclocal: error: /usr/local/bin/autom4te failed with exit status: 1
autoreconf: error: aclocal failed with exit status: 1
make[1]: *** [Makefile:903: build-only-libsndfile_x86_64-w64-mingw32.static] Error 1
make[1]: Leaving directory '/home/bark/mxe'
real	0m5,646s
user	0m4,455s
sys	0m0,188s
------------------------------------------------------------
[log]      /home/bark/mxe/log/libsndfile_x86_64-w64-mingw32.static

make: *** [Makefile:891: /home/bark/mxe/usr/x86_64-w64-mingw32.static/installed/libsndfile] Error 1

Далее смотрю лог, в нем:

cd '/home/bark/mxe/tmp-libsndfile-x86_64-w64-mingw32.static/libsndfile-1.1.0' && autoreconf -fi
configure.ac:345: error: macro PKG_INSTALLDIR is not defined; is a m4 file missing?
m4/ax_require_defined.m4:35: AX_REQUIRE_DEFINED is expanded from...
configure.ac:345: the top level
autom4te: error: /usr/bin/m4 failed with exit status: 1
aclocal: error: /usr/local/bin/autom4te failed with exit status: 1
autoreconf: error: aclocal failed with exit status: 1
make[1]: *** [Makefile:903: build-only-libsndfile_x86_64-w64-mingw32.static] Error 1
make[1]: Leaving directory '/home/bark/mxe'

Моя версия pkg:

pkg-config --version
0.29.1

Читаю про макрос PKG_INSTALLDIR:

PKG_INSTALLDIR(КАТАЛОГ)
Определяет переменную $pkgconfigdir как место, куда пакет должен установить pkg-config.
файлы .pc.

В mxe/tmp-libsndfile-x86_64-w64-mingw32.static/libsndfile-1.1.0/configure.ac указано:

dnl Require autoconf version >= 2.69
AC_PREREQ([2.69])

У меня

autoconf --version
autoconf (GNU Autoconf) 2.71

В этом файле configure.ac макрос PKG_INSTALLDIR упоминается два раза:

dnl Check for pkg-config outside the if statement.
PKG_PROG_PKG_CONFIG
AX_REQUIRE_DEFINED([PKG_INSTALLDIR])
PKG_INSTALLDIR

Версия Убунты 20.04 LTS.

Никто случайно не знает как это решить. Мысли вслух: может вручную создать директорию m4?

Заранее благодарен за ответы со существу.

 , , , ,

Gyros
()

Имитация фиксированного конвейера на современном OpenGL

Приветстсвую всех!

Пытаюсь воспроизвести древний пример 1996 года на opengl4

(чтобы рендерилась в точности картинка с использованием фиксированных функций - но до этого пока далеко).

Простенькая сцена. Для простоты вывожу только три плоскости: пол, левую и правую стенки.

Последовательные запуски дают разные варианты затенения:

первый вариант

второй

третий

Сталкивался ли кто-нибудь с таким эффектом? Чем он вызван?

В расчете модели освещения нет элементов случайности, так что в этом виноват не шейдер (вершинный/фрагментный).

Тут что-то с vbo?

Инициализация пола

void initFloor()
{

    // 1) Текстура
    GLfloat *textureData = make_texture(TEXDIM, TEXDIM);
    glGenTextures(1, &tex_id);

    glBindTexture(GL_TEXTURE_2D, tex_id);
    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
    glTexStorage2D(GL_TEXTURE_2D, 1, GL_R32F, TEXDIM, TEXDIM);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, TEXDIM, TEXDIM, GL_RED, GL_FLOAT, textureData);
    free(textureData);
    CHECK_GL_ERROR();
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_G, GL_RED);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_SWIZZLE_B, GL_RED);


    glActiveTexture(GL_TEXTURE0);
    CHECK_GL_ERROR();
    prog_set_uniform_int(&floorsh, "tex1", 0);

    // 2) Геометрия
    float vertexData[4*3]=
    {
         -100.f,  -100.f, -320.f,  
          100.f,  -100.f, -320.f,  
          100.f,  -100.f, -640.f,  
         -100.f,  -100.f, -640.f   
    };

    GLubyte colorData[4*3] =
    {
        200, 200, 200,
        200, 200, 200,
        200, 200, 200,
        200, 200, 200 
       
    };

    GLubyte texCoords[4*2] =
    {
        0, 0, 
        1, 0, 
        1, 1, 
        0, 1
    };

    GLuint indexList[2][3] =
    {
        {0, 1, 2},   // first triangle
        {0, 2, 3}    // second triangle
    };



    glGenBuffers(1, &vbo_floor_pos);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_pos);
    glBufferData(GL_ARRAY_BUFFER, 4*3 * sizeof(float), vertexData, GL_STATIC_DRAW);

    glGenBuffers(1, &vbo_floor_color);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_color);
    glBufferData(GL_ARRAY_BUFFER, 4*3 * sizeof(GLubyte), colorData, GL_STATIC_DRAW);

    glGenBuffers(1, &vbo_floor_tex);
    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_tex);
    glBufferData(GL_ARRAY_BUFFER, 4*2 * sizeof(float), texCoords, GL_STATIC_DRAW);

    glGenBuffers(1, &ebo_floor);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_floor);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2*3 * sizeof(GLuint), indexList, GL_STATIC_DRAW);

    

    glGenVertexArrays( 1, &vao_floor );
    glBindVertexArray(vao_floor);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_floor);

    

    glEnableVertexAttribArray(0);  // position
    glEnableVertexAttribArray(1);  // color
    glEnableVertexAttribArray(2);  // texture coords

    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_pos);
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_color);
    glVertexAttribPointer( 1, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, vbo_floor_tex);
    glVertexAttribPointer( 2, 2, GL_UNSIGNED_BYTE, GL_FALSE, 0, NULL );

    glBindVertexArray(0);
}

Отрисовка пола

void drawFloor()
{
    prog_use(&floorsh);

    glEnable(GL_TEXTURE_2D);
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex_id);
    
    glBindVertexArray(vao_floor);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo_floor);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    glBindVertexArray(0);
    glDisable(GL_TEXTURE_2D);
}

Инициализация левой и правой стены

/* left wall */
static float left_wall[12] = {-100.f, -100.f, -320.f,
                              -100.f, -100.f, -640.f,
                              -100.f,  100.f, -640.f,
                              -100.f,  100.f, -320.f };
static float left_normal[3] = {1.f, 0.f, 0.f};
static float left_color[3] = {165, 165, 165};
static struct PLANE left;

/* right wall */
static float right_wall[12] = {  100.f, -100.f, -320.f,
                                 100.f,  100.f, -320.f,
                                 100.f,  100.f, -640.f,
                                 100.f, -100.f, -640.f };
static float right_normal[3] = {-1.f, 0.f, 0.f};
static float right_color[3] = {165, 165, 165};
static struct PLANE right;

void plane_init(PLANE *plane, const float *points, float *normal, float *color)
{
    
    float vertexData[4*3]=
    {
          points[0],  points[ 1], points[ 2],  
          points[3],  points[ 4], points[ 5], 
          points[6],  points[ 7], points[ 8], 
          points[9],  points[10], points[11]
    };

    GLubyte colorData[4*3] =
    {
        color[0], color[1], color[2],
        color[0], color[1], color[2],
        color[0], color[1], color[2],
        color[0], color[1], color[2]
    };

    GLubyte texCoords[4*2] =
    {
        0, 0, 
        1, 0, 
        1, 1, 
        0, 1
    };

    GLubyte normalData[4*3] =
    {
        normal[0], normal[1], normal[2],
        normal[0], normal[1], normal[2],
        normal[0], normal[1], normal[2],
        normal[0], normal[1], normal[2] 
    };

    GLuint indexList[2][3] =
    {
        {0, 1, 2},   // first triangle
        {0, 2, 3}    // second triangle
    };



    glGenBuffers(1, &plane->vbo_pos);
    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_pos);
    glBufferData(GL_ARRAY_BUFFER, 4*3 * sizeof(float), vertexData, GL_STATIC_DRAW);

    glGenBuffers(1, &plane->vbo_color);
    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_color);
    glBufferData(GL_ARRAY_BUFFER, 4*3 * sizeof(GLubyte), colorData, GL_STATIC_DRAW);

    glGenBuffers(1, &plane->vbo_tex);
    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_tex);
    glBufferData(GL_ARRAY_BUFFER, 4*2 * sizeof(float), texCoords, GL_STATIC_DRAW);

    glGenBuffers(1, &plane->vbo_normal);
    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_normal);
    glBufferData(GL_ARRAY_BUFFER, 4*3 * sizeof(float), normalData, GL_STATIC_DRAW);

    glGenBuffers(1, &plane->ebo);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane->ebo);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2*3 * sizeof(GLuint), indexList, GL_STATIC_DRAW);

    

    glGenVertexArrays( 1, &plane->vao );
    glBindVertexArray(plane->vao);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane->ebo);

    

    glEnableVertexAttribArray(0);  // position
    glEnableVertexAttribArray(1);  // color
    glEnableVertexAttribArray(2);  // texture coords
    glEnableVertexAttribArray(3);  // normal

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_pos);
    glVertexAttribPointer( 0, 3, GL_FLOAT, GL_FALSE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_color);
    glVertexAttribPointer( 1, 3, GL_UNSIGNED_BYTE, GL_TRUE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_tex);
    glVertexAttribPointer( 2, 2, GL_UNSIGNED_BYTE, GL_FALSE, 0, NULL );

    glBindBuffer(GL_ARRAY_BUFFER, plane->vbo_normal);
    glVertexAttribPointer( 3, 3, GL_FLOAT, GL_FALSE, 0, NULL );

    glBindVertexArray(0);

}

void plane_draw(PLANE *plane)
{
    glBindVertexArray(plane->vao);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, plane->ebo);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);

    glBindVertexArray(0);
}

Инициализация шейдеров:

void init_scene()
{
    glClear ( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT) ;
   
    glClearColor(0.5f, 0.5f, 0.5f, 1.0f );  

    prog_create(&floorsh);
    prog_attach_shader_from_file(&floorsh, FLOOR_VERTEX_SHADER_NAME);
    prog_attach_shader_from_file(&floorsh, FLOOR_FRAGMENT_SHADER_NAME);
    prog_link(&floorsh);
    prog_use(&floorsh);
    initFloor();
    
    
    
    prog_create(&wallsh);
    prog_attach_shader_from_file(&wallsh, WALL_VERTEX_SHADER_NAME);
    prog_attach_shader_from_file(&wallsh, WALL_FRAGMENT_SHADER_NAME);
    prog_link(&wallsh);
    prog_use(&wallsh);
    initWalls();
      
 
    prog_set_uniform_3f(&wallsh, "lightSource.ambient",  1.0f, 1.0f, 1.0f);  
    prog_set_uniform_3f(&wallsh, "lightSource.diffuse",  1.0f, 1.0f, 1.0f); 
    prog_set_uniform_3f(&wallsh, "lightSource.specular", 1.0f, 1.0f, 1.0f);  
    prog_set_uniform_3f(&wallsh, "lightSource.position", 50.f, 50.f, -320.f);

    prog_set_uniform_3f(&wallsh, "lightModel.ambient",  1.0f, 1.0f, 1.0f);  
    prog_set_uniform_3f(&wallsh, "material.emission",   1.0f, 1.0f, 1.0f); 
    prog_set_uniform_3f(&wallsh, "material.ambient",    1.0f, 1.0f, 1.0f);  
    prog_set_uniform_3f(&wallsh, "material.diffuse",    1.0f, 1.0f, 1.0f); 
    prog_set_uniform_3f(&wallsh, "material.specular",   1.0f, 1.0f, 1.0f); 
    prog_set_uniform_float(&wallsh, "material.shininess",   10.0f); 

    mat4_identity(&model);
    mat4_identity(&view);
   
    MAT4 MV; 
    mat4_multiply(&MV, &view,  &model);
    prog_set_uniform_mat4(&wallsh, "modelViewMatrix", &MV);

    MAT3 NormalMatrix;
    NormalMatrix.M[0] = MV.M[0];     NormalMatrix.M[3] = MV.M[4];     NormalMatrix.M[6] = MV.M[8];
    NormalMatrix.M[1] = MV.M[1];     NormalMatrix.M[4] = MV.M[5];     NormalMatrix.M[7] = MV.M[9];
    NormalMatrix.M[2] = MV.M[2];     NormalMatrix.M[5] = MV.M[6];     NormalMatrix.M[8] = MV.M[10];
    prog_set_uniform_mat3(&wallsh,"normalMatrix", &NormalMatrix);

    
    mat4_perspective_projection(&projection, -FRUSTDIM, FRUSTDIM, -FRUSTDIM, FRUSTDIM, FRUSTNEAR, FRUSTFAR);
    prog_set_uniform_mat4(&wallsh, "projectionMatrix", &projection);
    

    glEnable(GL_DEPTH_TEST);
    //glPolygonMode(GL_FRONT, GL_FILL);

    //glCullFace(GL_BACK);

    CHECK_GL_ERROR();
}

Заранее благодарю за осмысленные ответы и помощь!

 , , ,

Gyros
()

Названия для размеров часто используемых буферов

Приветствую всех!

Сделал так:

#define GIANT_SIZE     1024*32
#define HUGE_SIZE      1024*16 
#define LARGE_SIZE     1024*8 
#define BIG_SIZE       1024 
#define MIDDLE_SIZE    512
#define MEDIUM_SIZE    256
#define SMALL_SIZE     128 
#define LITTLE_SIZE    64 
#define TINY_SIZE      32 

Стильно получилось?

Часто требуется, например, считать строку из файла, и чтобы не плодить магических констант, вместо 512 писать MIDDLE_SIZE

...
while (!feof(fp))
{
    char buff[MIDDLE_SIZE];
    fgets(buff, MIDDLE_SIZE, fp);
    buff[MIDDLE_SIZE-1]='\0';
    char* line = str_dup(buff);
    str_trim(line);
...

Например, загрузка матрицы из файла формата (нарочно зашумленный пробелами и tab-ами):



DIM1=	3
	
  DIM2 = 7


{
   	 0.935    0.674    -1.687    0.468  2.436   -1.743  0.275

   	 0.111    0.346    0.368   0.907    -7.346     -0.235    -0.139  
0.436    -0.134    -1.047    0.879    -1.051  -0.367         -0.196

}
	

выглядит вот так

void matrix_load( MATRIX* A, const char* fileName)
{
    FILE* fp;
    bool b_is_dim1_read=false;
    bool b_is_dim2_read=false;
    unsigned int dim1, dim2;
    bool begin=false;
    bool end = false;
    int row_count = 0;


    if ((fp = fopen(fileName,"r")) == NULL)
    {
      fprintf(stderr,"File '%s' open failed\n", fileName);
      enter_pause();
      exit(EXIT_FAILURE);
    }
    else
    {
        while (!feof(fp))
        {
            char buff[MIDDLE_SIZE];
            fgets(buff, MIDDLE_SIZE, fp);
            buff[MIDDLE_SIZE-1]='\0';
            char* line = str_dup(buff); // 
            str_trim(line);  // обрезаем '\t','\v', '\f', '\n', '\r', ' '      

            if (0==strlen(line)) // если после обрезки строка пустая, то пропускаем обработку
            {
                free(line);
                continue;
            }
            
            if (line[0] == 'D' && line[1] == 'I' && line[2]== 'M') // если встретилось "DIM"
            {
                Tokens* dim  = tokens_new(2);
                string_split(dim, line, "="); // разбиваем строку по '='
                

                if (line[3]== '1' || line[3]== '2') // DIM1 или DIM2
                {
                    errno = 0;
                    char *endptr;
                    unsigned int d = strtoul(dim->array[1]->data, &endptr, 10);
                    
                    if (*endptr != '\0' || errno !=0 || d==0 || d>30) // не более 30x30
                    {
                        fprintf(stderr,"Error: dimension wrong '%s'\n", dim->array[1]->data);
                        tokens_free(dim);
                        free(line);
                        enter_pause();
                        exit(EXIT_FAILURE);
                    }
                    
                    switch (line[3])
                    {
                    case '1':
                        dim1 = d;
                        b_is_dim1_read = true;
                        break;

                    case '2':
                        dim2 = d;
                        b_is_dim2_read = true;
                        break;

                    }
                }
                
                 // если все размерности считаны, то выделяем память для матрицы
                if (b_is_dim1_read && b_is_dim2_read)
                {
                    matrix_create(A, dim1, dim2);
                }

                tokens_clear(dim);
                tokens_free(dim);
            }

            

            if (line[0] =='{') { begin=true; free(line); continue; } // признак начала значений матрицы
            if (line[0] =='}') { end=true;   free(line); continue; }
            if (begin && !end)
            {
                //printf("%s\n", line);
                Tokens* row  = tokens_new(dim2); // по кол-ву элементов в строке
                string_split(row, line, " ");

                // если столбцов недостаточно или строк больше заявленных
                if (dim2 != row->size || row_count >= dim1)
                {
                    fprintf(stderr,"Error: Invalid file format '%s'\n", fileName);
                    enter_pause();
                    exit(EXIT_FAILURE);
                }

                // заполнение строки матрицы
                for (int j=0; j<dim2; ++j)
                {
                    
                    errno = 0;
                    char *endptr;
                    double value = strtod(row->array[j]->data, &endptr);
                    if (*endptr != '\0' || errno != 0 || 10 < strlen(row->array[j]->data) ) //не более 10-значное число
                    {
                        fprintf(stderr,"Error: wrong value '%s'\n", row->array[j]->data);
                        tokens_free(row);
                        free(line);
                        matrix_free(A);
                        enter_pause();
                        exit(EXIT_FAILURE);
                    }
                    matrix_set_elem(A, row_count, j,  value);
                }
                row_count++;
                tokens_clear(row);
                tokens_free(row);
            }


            free(line);
        }
        fclose(fp);

        if (row_count != dim1) // недочитали заявленные dim1 строк
        {
            fprintf(stderr,"Error: Invalid file format '%s'\n", fileName);
            enter_pause();
            exit(EXIT_FAILURE);
        }
    }

}

Функция str_dup:

char *str_dup(char const *in)
{
    if ( !in ) return NULL;
    size_t len = strlen(in);
    char *out = malloc(len+1);
    strncpy(out, in, len+1);
    return out;
}

Буду рад услышать отзывы о стиле.

 , , ,

Gyros
()

Форматирование даты-времени для лога: strftime не работает с mingw?

Всех приветствую!

Необходимо выводить дату-время в лог-файл.

char* get_datetime_str_alt1(char *str_datetime)
{
    char buff[64]={'\0'};

    struct timespec ts;
    clock_gettime(CLOCK_REALTIME, &ts);
  
    strftime(buff, sizeof(buff), "%e-%b-%Y %Z %T", localtime(&ts.tv_sec));
    sprintf(str_datetime, "%s", buff);
       
    return str_datetime;
}


char* get_datetime_str_alt2(char *str_datetime)
{
    char buff[64]={'\0'};
       
    time_t t = time(NULL);
    struct tm *local = localtime(&t);
  
    strftime(buff, sizeof(buff), "%e-%b-%Y %Z %H:%M:%S", local);
    sprintf(str_datetime, "%s", buff);
       
    return str_datetime;
}

Эти два варианта работают после gcc

1-Aug-2024 MSK 12:32:45: Start!
1-Aug-2024 MSK 12:32:45: Bla-bla
1-Aug-2024 MSK 12:32:46: End!

, но ничего не выводят после mingw:

: Start!
: Bla-bla
: End!

Работает отлично только

char* get_datetime_str(char *str_datetime)
{
    time_t t = time(NULL);
        
    sprintf(str_datetime, "%s", ctime(&t) );
    char *p = strchr(str_datetime, '\n');
    *p = '\0';
 
    return str_datetime;
}

Но форматирование уже выбираю не я:

Thu Aug 01 12:13:08 2024: Start!
Thu Aug 01 12:13:08 2024: Bla-bla
Thu Aug 01 12:13:09 2024: End!

По идее и так работает. Но все таки какая-то неудовлетворенность остается. Сталкивался кто-нибудь с подобным эффектом?

Подозреваю нужно обновлять mingw, но так не хочется: столько библиотек опять устанавливать (к тому же я уже забыл как это делал).

PS gcc (Ubuntu 9.4.0-1ubuntu1~20.04.2) 9.4.0

x86_64-w64-mingw32-gcc (GCC) 9.3-win32 20200320 wincrt

 , , , ,

Gyros
()

printf vs fprintf(stderr)

Всех приветствую!

Задался таким вопросом: а нужно ли городить

 fprintf(stderr, "Error: bla-bla\n");

вместо простого

printf("Error: bla-bla\n");

Ведь результат один и тот же.

Когда необходимо разделять stderr и stdout? Вообще, когда и как может использоваться stderr?

PS Заранее благодарю за ответы.

 , ,

Gyros
()

Есть ли тема курсора, чтобы при нажатии кнопки мыши была анимация курсора?

Приветствую всех!

Не подскажете существует ли тема курсора (для xfce, xubuntu), чтобы принажатии кнопки мыши производилась какая-нибудь анимация, например маленький фейерверк исходящий от курсора или он как-то бы подсвечивался интересно.

Или, если нет темы, то как сделать подсветку курсора при нажатии.

Заранее благодарю за содержательные ответы.

 , , , ,

Gyros
()

Поле редактирования в Nuklear

Всех приветствую!

Имеется проблема с работой nk_edit_string, библиотека Nuklear.

Суть: вводим в поле целое число и нажимаем кнопочку рядом, число выводится в консоле (для отладки).

int F=5; // глобальная
...

static char text[64];
static int text_len;
active = nk_edit_string(ctx, NK_EDIT_SIMPLE, text, &text_len, 64, nk_filter_decimal);
            if (nk_button_label(ctx, "->")) // || active & NK_EDIT_COMMITED)
{
   text_len = strlen(text);
   if (text_len !=0 && text_len<8)
   {
       F = atoi(text);
       printf("F=%d\n", F);
       memset(text, '\0', 64);
       text_len=0;
   }
   printf("text=%s\n", text);
}
...

Тест 1: ввели 77, вывод: F=77, text="";

Тест 2: ввели 555, но тут же передумали, стерли и снова набрали 77, вывод: F=775, text="";

Получается буфер text был «555», но был перебит «775», т.е. он не чиститься при каждом новом вводе/редактировании.

Кто-нибудь умеет правильно использовать NK_EDIT_SIMPLE, чтобы не было такого эффекта (вернее сказать, дефекта)?

 , , ,

Gyros
()

Числа с плавающей запятой. Откуда взялся минус и как его убрать?

Тестовый пример, показывающий суть явления:

#include <stdio.h>
int main()
{
    float right=-2.0f, left=2.0f; 
    float res = (right+left)/(right-left);
    printf("%5.12e\n", res);

    float test = -0.00000000000000424f;
    printf("%3.3f\n", test);
}

Результат:

-0.000000000000e+00
-0.000

Понятно, что после right-left знаковый бит становится 1. Но выглядит (когда выводишь на экран с %3.3f) так как будто есть где-то далеко после нулей числа, например -0.00000000000000424. А на самом деле их нет. Это ноль, только со знаком (IEEE754 это допускает). Но с математической точки зрения и при выводе матрицы нам хотелось бы видеть настоящий ноль (в математике он один) без знака. Кто-нибудь сталкивался с такой «проблемой»? Как красиво сделать в программе, чтобы ноль был единственным, без знака. Есть ли изящные решения? Просто не хочется чтобы в матрице было -0.000, это может сбить с толка того, кто будет смотреть вывод на экран или распечатку, по уже выше описанной причине.

 , , ,

Gyros
()

Imgui и чистый C

Приветствую всех! Никто не знает как собрать программу, если библиотека Imgui использует C++, а main.c и др. используемые библиотеки написаны на чистом C (C11). Вызовы Imgui происходят только в одном main.c Как быть? Может есть какой-нибудь способ собрать. Или отказываться от Imgui? А есть ли альтернатива пользовательского интерфейса для OpenGL на C?

 , , , ,

Gyros
()

Программирование анимации персонажа. Есть проблема

Всех приветствую! Хочу двигать персонаж вправо на 10.0f ровно за свое заданное время: 2 сек, 0.5 сек и т.п.

Имеются следующие функции и глобальные переменные (очищенный от несущественного псевдокод):

float personage_X=-5.0f, personage_Y=-5.0f;
float distance_X=10.0, distance_Y=0.0;
float dX, dY;
double DELTA_T = 0.01667; //среднее значение delta_T даваемое программой 
                            //(по сути это 1000/60=16.6(6) мс/кадр)
double last_T_move;
double duration_T;
int duration_tick;
bool bmoveLeft  = false;
bool bmoveRight = false;



moveRight
{
   bmoveRight = true; // начинаю движение
   duration_T = 0.9;   // длительность в сек
   duration_tick = (int) (duration_T/DELTA_T); // кол-во тиков(кадров) для перемещения
   dX = distance_X/duration_tick;                   // шаг перемещения
   last_T_move = get_time();
}

update
{
  printf("update()\n");
  if (bmoveRight)
  {
      personage_X += dX;
      printf("now_T - last_T_move = %5.7f\n", now_T - last_T_move);
      if (now_T - last_T_move >= duration_T )
      {
         bmoveRight = false; // остановить движение
      }
    }
}

idle
{
  const double now_T = get_time();
  const double delta_T = now_T - last_T;
  last_T = now_T;
  printf("delta_T = %5.5f\n", delta_T);

  update(now_T);

  redisplay();
}

display
{
  printf("display()\n");
  render_personage();

  swap_buffers();
}

Вывод консоли работающей программы:

( читать дальше... )

1) Теперь я начинаю движение, например за 2.2 сек вправо на 10:

personage coords: [-5.000, -5.000]
duration_tick = 131 // 131 кадр необходимо для достижения конечной точки перемещения 
dX = 0.07634        // шаг
now_T - last_T_move = 0.0156779
now_T - last_T_move = 0.0324781
now_T - last_T_move = 0.0491800
now_T - last_T_move = 0.0658500
now_T - last_T_move = 0.0825200
...
now_T - last_T_move = 2.1999640
now_T - last_T_move = 2.2166250
personage coords: [5.153, -5.000]  //  в идеале должно быть [5.000, -5.000]
                                   //  еще только маленькая погрешность

2) Движение за 0.9 сек вправо на 10:

personage coords: [-5.000, -5.000]
duration_tick = 53 // 53 кадра необходимо для достижения конечной точки перемещения 
dX = 0.18868       // шаг
now_T - last_T_move = 0.0135901
now_T - last_T_move = 0.0302720
now_T - last_T_move = 0.0469420
now_T - last_T_move = 0.0636110
...
now_T - last_T_move = 0.9139049
personage coords: [5.377, -5.000]  //  в идеале должно быть [5.000, -5.000]
                                   //  уже существенная погрешность

3) Движение за 0.2 сек вправо на 10:

personage coords: [-5.000, -5.000]
duration_tick = 11
dX = 0.90909
now_T - last_T_move = 0.0133729
now_T - last_T_move = 0.0302980
now_T - last_T_move = 0.0469708
now_T - last_T_move = 0.0636489
now_T - last_T_move = 0.0803308
...
now_T - last_T_move = 0.1970379
now_T - last_T_move = 0.2136910
personage coords: [6.818, -5.000]  // в идеале должно быть [5.000, -5.000]
                                   //  бешенейшая погрешность (!)
                                   // Alarm! Что делать?

Из трех экспериментов видно, что чем быстрее я хочу переместиться, то тем дальше перелетаю требуемую конечную точку.

Хотелось бы услышать компетентное мнение по устранению данной проблемы и/или возможного изменения подхода к анимации в принципе. Спасибо за помощь!

 , , , ,

Gyros
()

Не хватает библиотеки при сборке cocos2d-x, а она есть!

~/cocos2d-x-3.17.2/cmake-build$ make
[  1%] Built target ext_unzip
[  3%] Built target ext_recast
[  3%] Built target ext_tinyxml2
[  3%] Built target ext_xxhash
[  3%] Built target ext_xxtea
[  3%] Built target ext_clipper
[  4%] Built target ext_edtaa3func
[  4%] Built target ext_convertUTF
[  4%] Built target ext_poly2tri
[  5%] Built target ext_md5
[  5%] Built target external
[ 70%] Built target cocos2d
[ 71%] Built target ext_tolua
[ 72%] Built target ext_luasocket
[ 79%] Built target luacocos2d
[ 84%] Built target jscocos2d
[ 84%] Linking CXX executable ../../../bin/cpp-empty-test/cpp-empty-test
/usr/bin/ld: ../../../../external/linux-specific/fmod/prebuilt/64-bit/libfmod.so: .dynsym local symbol at index 2 (>= sh_info of 2)
/usr/bin/ld: ../../../../external/linux-specific/fmod/prebuilt/64-bit/libfmod.so: .dynsym local symbol at index 3 (>= sh_info of 2)
/usr/bin/ld: ../../../../external/linux-specific/fmod/prebuilt/64-bit/libfmod.so: .dynsym local symbol at index 4 (>= sh_info of 2)
/usr/bin/ld: cannot find -lXxf86vm
collect2: error: ld returned 1 exit status
make[2]: *** [engine/tests/cpp-empty-test/CMakeFiles/cpp-empty-test.dir/build.make:153: bin/cpp-empty-test/cpp-empty-test] Error 1
make[1]: *** [CMakeFiles/Makefile2:1292: engine/tests/cpp-empty-test/CMakeFiles/cpp-empty-test.dir/all] Error 2
make: *** [Makefile:84: all] Error 2
~/cocos2d-x-3.17.2/cmake-build$ 

Я так понимаю, что библиотеки собрались, а вот примеры не хотят. Кто знает в чем причина? Заранее благодарен за любые содержательные ответы.

PS. Файлы libXxf86vm.so.1 и libXxf86vm.so.1.0.0 в /usr/lib/x86_64-linux-gnu/ присутствуют.

PS2. sudo apt-get update && sudo apt-get install libxxf86vm-dev пробовал.

 , ,

Gyros
()

vbo, vao и шейдеры

Всем привет! Требуется отправить 6 вершин в GPU. А далее выводить сначала как два анимированных треугольника: (1,2,3)(3,4,1). Потом, тоже как два треугольника, но (4,1,2)(2,3,4). Как сделать так, чтобы не обновлять геометрию в основной программе, т.е. не очищать vao и создавать новый буфер (по сути из тех же самых вершин), и снова его отправлять в GPU. Может индексация тут поможет (можно ли обновлять только буфер индексов?) или в геометрическом шейдере что-то надо делать.

PS: opengl-4

 , , ,

Gyros
()

FreeType2 и mingw32: как получить библиотеку, с которой можно собрать проект для Windows

Всем добрый вечер! Собственно вопрос в заголовке. Конкрентно интересует для версии FreeType 2.11.1.

Готовую библиотеку что-то навскидку найти не удалось.

Пробовал собирать на месте. Обычную для Linux и g++ без проблем. А для mingw32

В файле INSTALL.GNU говориться заменить config.mk на w32-mingw32.mk из freetype-2.11.1/builds/windows/ Но это ничего не дает:

make CC="x86_64-w64-mingw32-c++"
Вывод:
make: type: Command not found
make: *** No rule to make target '.\src\tools\apinames.c', needed by '.\objs\apinames.exe'.  Stop.

PS Т.е. я правильно понимаю что для того чтобы получить библиотеку (которую можно будет кинуть в /usr/x86_64-w64-mingw32/lib/ и далее использовать для др. проектов для Windows) необходимо собрать исходники FreeType компилятором mingw32?

 

Gyros
()

Cmake, mingw32 и сборка под Ubuntu для получения exe-файла

Добрый день всем! Есть простенькое графическое приложение, которое без проблем собирается вызовом:

x86_64-w64-mingw32-c++  sailboat.c  -o sailboat.exe  -lglfw3dll -lglfw3 -static-libgcc -static-libstdc++  -lopengl32  -Wl,--subsystem,windows
На выходе получаем exe-шник, который запускается под Windows (или Wine).

Однако, если использовать CMake:

cmake_minimum_required(VERSION 3.0)	# Проверка версии CMake.
					

set (PROJECT sailboat) 		        # Название проекта
project(${PROJECT})

set(OpenGL_GL_PREFERENCE LEGACY)
find_package(OpenGL REQUIRED)
find_package(glfw3  REQUIRED)
include_directories(${OPENGL_INCLUDE_DIR})


find_library(PTHREAD_LIB pthread)

                                   # Установка переменной со списком исходников для исполняемого файла
#set (SOURCES  gl_core_4_3.c)
#set (HEADERS  gl_core_4_3.h)
set (LIBS ${LIBS} ${OPENGL_LIBRARY} ${GLFW_LIBRARIES} )


set (MINGW=ON)
set (CMAKE_SYSTEM_NAME=Windows)
#set_target_properties (${PROJECT} PROPERTIES CMAKE_WIN32_EXECUTABLE True)

set( CMAKE_SHARED_LIBRARY_LINK_C_FLAGS "" )
set( CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "" )

set (BUILD_SHARED_LIBS=OFF)
set (BUILD_CLAR=OFF)
set (THREADSAFE=ON)

set (CMAKE_C_COMPILER   /usr/bin/x86_64-w64-mingw32-c++)
set (CMAKE_CXX_COMPILER /usr/bin/x86_64-w64-mingw32-c++)

set(CMAKE_C_FLAGS   "${CMAKE_C_FLAGS}   -static")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -static")

set(CMAKE_LIBRARY_PATH /usr/x86_64-w64-mingw32/lib)

set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--subsystem,windows")


add_executable (${PROJECT} WIN32 ${HEADERS} ${SOURCES} sailboat.c)    # Создает исполняемый файл с именем PROJECT

set_target_properties (${PROJECT} PROPERTIES LINK_FLAGS_DEBUG   "/SUBSYSTEM:windows")
set_target_properties (${PROJECT} PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:windows")       

#set(CMAKE_EXE_LINKER_FLAGS "-static -static-libgcc -static-libstdc++ -lglfw3dll")

target_include_directories(${PROJECT} PUBLIC
                           $<BUILD_INTERFACE:${CMAKE_CURRENT_LIST_DIR}/include>
                           $<INSTALL_INTERFACE:include>)


				  # Линковка программы с библиотеками
#target_link_libraries( PUBLIC glfw  ${PTHREAD_LIB} )
target_link_libraries(${PROJECT} PUBLIC ${OPENGL_gl_LIBRARY} glfw)
то происходит такая вещь:

[ 50%] Linking C executable sailboat
/usr/bin/x86_64-w64-mingw32-ld: cannot find -lGL
/usr/bin/x86_64-w64-mingw32-ld: cannot find -lrt
/usr/bin/x86_64-w64-mingw32-ld: cannot find -ldl
/usr/bin/x86_64-w64-mingw32-ld: cannot find -lX11
collect2: error: ld returned 1 exit status
make[2]: *** [CMakeFiles/sailboat.dir/build.make:89: sailboat] Error 1
make[1]: *** [CMakeFiles/Makefile2:76: CMakeFiles/sailboat.dir/all] Error 2
make: *** [Makefile:84: all] Error 2

Вообще-то линкер не должен требовать этих библиотек для сборки для Windows. В чем причина?

PS Извините, я новичок в CMake, поэтому CMakeLists.txt такой сумбурный.

 

Gyros
()

RSS подписка на новые темы