Portál AbcLinuxu, 5. května 2025 21:07

Dotaz: Změna typu existujících integerů v poli

25.2.2020 09:33 Jirka | skóre: 25
Změna typu existujících integerů v poli
Přečteno: 674×
Odpovědět | Admin
Zdravím všechny,
Mám např. uint32_t array[10000000] s existujícími obrazovými daty, se kterými provedu nějaké výpočty, nakonec všechny prvky v poli odmocním, takže se vejdou do 16bit prostoru a také je chci uložit pomocí fwrite jako 16bit raw.

Dá se to nějak provést bez tvorby ještě jednoho pole uint16_t o stejné velikosti? Ideálně změnit typ už vytvořeného pole, tj. na stejných adresách se zachováním hodnot a to pak uložit. Nebo přesvědčit fwrite, aby ukládal jen posledních 16bitů z každého prvku a to ostatní ignoroval (tedy ani nevyplňoval nulama). Raspberry jedno velké pole ustojí, se dvěma už má občas problém.
Díky.
Dokud to funguje, nešťourej se v tom!...

Řešení dotazu:


Nástroje: Začni sledovat (0) ?Zašle upozornění na váš email při vložení nového komentáře.

Odpovědi

Řešení 1× (Jirka (tazatel))
25.2.2020 09:56 finn | skóre: 43 | blog: finnlandia | 49° 44´/13° 22´
Rozbalit Rozbalit vše Re: Změna typu existujících integerů v poli
Odpovědět | | Sbalit | Link | Blokovat | Admin
Vytvořit si pomocné pole uint16_t temparr[] a ve smyčce do něj ukládat části původního pole a ty zapisovat?

#define TA_LEN 1000;

static inline void zkonvertuj_dalsi_cast_pole(uint16_ * temparr, uint32_t * array, size_t index, size_t TA_LEN)
{
  ...
}

void foo(void)
{
  FILE file;
  size_t index = 0;
  uint16_t temparr[TA_LEN];
  ...
  while(pole_jeste_neni_zpracovano)
  {
    zkonvertuj_dalsi_cast_pole(temparr, array, index, TA_LEN);
    fwrite(temparr, sizeof(temparr), 1, file);
    index += TA_LEN;
  }
  ...
}
V příkladu samozřejmě není ošetřená případná chyba fwrite() nebo stav kdy TA_LEN není soudělné s počtem prvků pole array[]
Užívej dne – možná je tvůj poslední.
25.2.2020 10:19 Jirka | skóre: 25
Rozbalit Rozbalit vše Re: Změna typu existujících integerů v poli
Díky, dobrej nápad! :-)
Přesná velikost pole je [12216864], to je dělitelné 32, takže bude stačit pole uint16_t [381777], to už by mělo projít.
Dokud to funguje, nešťourej se v tom!...
25.2.2020 12:48 debian+
Rozbalit Rozbalit vše Re: Změna typu existujících integerů v poli
Odpovědět | | Sbalit | Link | Blokovat | Admin
Co tak bez dalsieho pomocneho ukladat?
uint32_t array[10000000];
uint32_t *index;
size_t i;

for(index=array, i=0; i <= 10000000; i++, index++)
{
	fwrite(*((uint16_t) index), sizefof(uint16_t), 1, FD);
}

/* este raz a citatelnejsie */
uint32_t array[10000000];
uint32_t *index;
uint16_t u16;
size_t i;

for(index=array, i=0; i <= 10000000; i++, index++)
{
	u16=(uint16_t) *index;
	fwrite(u16, sizefof(uint16_t), 1, FD);
}
Ono takto definovane by sa vo funkcie malo vytvarat na zasobniku. A to nemusi az tak v tentokrat u Andruido prospievat. Nechces pripadne allokovat pre beh programu tuto pamet cez malloc.
25.2.2020 13:00 debian+
Rozbalit Rozbalit vše Re: Změna typu existujících integerů v poli
Na druhej strane, preco ukladat fwrite po 1 bajte, ked sa da naraz? Hm, to nove pomocne pole sa potom zide. Alebo to mozes skonvertovat v tom istom poli.
25.2.2020 14:03 finn | skóre: 43 | blog: finnlandia | 49° 44´/13° 22´
Rozbalit Rozbalit vše Re: Změna typu existujících integerů v poli
Tipuju, že tohle bude násobně až řádově pomalejší oproti zápisu po blocích.
Užívej dne – možná je tvůj poslední.
25.2.2020 19:51 Andrej | skóre: 51 | blog: Republic of Mordor
Rozbalit Rozbalit vše Re: Změna typu existujících integerů v poli

Ůůůfff. Tohle ale mlčky předpokládá Little Endian, kde se dá jenom tak přetypovat uint32_t* na uint16_t* a ty dolní byty tam budou. Na Big Endian tam bude všude nula (horní byty).

25.2.2020 19:53 Andrej | skóre: 51 | blog: Republic of Mordor
Rozbalit Rozbalit vše Re: Změna typu existujících integerů v poli

Ne, beru zpět, neumím číst. Pointer se tady nepřetypuje, takže je to OK.

25.2.2020 19:45 Andrej | skóre: 51 | blog: Republic of Mordor
Rozbalit Rozbalit vše Re: Změna typu existujících integerů v poli
Odpovědět | | Sbalit | Link | Blokovat | Admin
Dá se to nějak provést bez tvorby ještě jednoho pole uint16_t o stejné velikosti?

Ano. Například nějak tahle (convert_in_place(...)):

#include <errno.h>
#include <fcntl.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

static const size_t SIZE = 100000;
typedef uint16_t narrow_array_t[SIZE];
typedef uint32_t wide_array_t[SIZE];
typedef uint16_t (*narrow_array_ptr)[SIZE];
typedef uint32_t (*wide_array_ptr)[SIZE];

////////////////////////////////////////////////////////////////////////////////
static narrow_array_ptr convert_in_place(const wide_array_ptr wide_array) {
  const uint32_t *source = *wide_array;
  uint16_t *dest = (uint16_t*)source;
  const uint16_t *const end = dest + SIZE;
  while (dest < end) *dest++ = *source++;
  return realloc(wide_array, sizeof(narrow_array_t));  // free extra memory
  // return (narrow_array_ptr)wide_array;              // keep extra memory
}
////////////////////////////////////////////////////////////////////////////////

static int dump_array_to_file(const char *const file_name,
                              const narrow_array_ptr narrow_array) {
  const int output = open(file_name,
                          O_WRONLY | O_CREAT | O_TRUNC,
                          S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH);
  if (output == -1) {
    fputs(strerror(errno), stderr);
    return EXIT_FAILURE;
  }
  int result = EXIT_SUCCESS;
  size_t to_write = sizeof(narrow_array_t);
  uint8_t *buffer = (uint8_t*)narrow_array;
  while (to_write) {
    const ssize_t written = write(output, buffer, to_write);
    if (written == -1) {
      result = EXIT_FAILURE;
      fputs(strerror(errno), stderr);
      break;
    }
    buffer += written;
    to_write -= written;
  }
  if (close(output) == -1) {
    fputs(strerror(errno), stderr);
    return EXIT_FAILURE;
  }
  return result;
}

int main() {
  // Allocate and populate an array of 32-bit integers.
  uint32_t (*const wide_array)[SIZE] = malloc(sizeof(wide_array_t));
  if (!wide_array) {
    fputs(strerror(errno), stderr);
    return EXIT_FAILURE;
  }
  for (size_t i = 0; i < SIZE; ++i) (*wide_array)[i] = i % 16384;

  // Compact 32-bit integers into 16-bit integers in-place.
  uint16_t (*const narrow_array)[SIZE] = convert_in_place(wide_array);
  
  // Write compacted array to standard output, just for fun.
  const uint16_t *const end = *narrow_array + SIZE;
  for (uint16_t *number = *narrow_array; number < end; ++number)
    printf("%d, ", *number);  // unchecked!
  putchar('\n');              // unchecked!

  // Write the compacted array into a binary file.
  int result = dump_array_to_file("/tmp/output", narrow_array);
  
  free(narrow_array);
  return result;
}

Pokud se nepletu, tento^^^ kód nezávisí na endianness, protože nedělá žádné podivné bitové operace. Tedy na BE vyrobí binární soubor v BE, na LE vyrobí binární soubor v LE. (A pokud se pletu, hned se mi bude někdo posmívat, takže dobře mi tak.)

Nebo přesvědčit fwrite, aby ukládal jen posledních 16bitů z každého prvku a to ostatní ignoroval (tedy ani nevyplňoval nulama).

Ano, tohle by taky šlo, ale musel by se ten fwrite() (nebo write()) volat SIZE-krát, vždycky na ty 2 byty, což by bylo celkem ošklivé a navíc by to bylo závislé na endianness, tj. muselo by se podle LE/BE správně určit, které 2 byty vypsat.

25.2.2020 20:44 rastos | skóre: 63 | blog: rastos
Rozbalit Rozbalit vše Re: Změna typu existujících integerů v poli
Ergo
uint16_t *tmp=(uint16_t*)array;
for (i=0;i<10000000;i++,tmp++)
  *tmp=array[i];
fwrite(array,10000000,sizeof(uint16_t),FD);
Načo si tam písal tých ostatných 76 riadkov?
25.2.2020 21:14 Jirka | skóre: 25
Rozbalit Rozbalit vše Re: Změna typu existujících integerů v poli
Odpovědět | | Sbalit | Link | Blokovat | Admin
Tak díky všem, hoši, to by stačilo, už to zbytečně komplikujete. :-D
Dokud to funguje, nešťourej se v tom!...
25.2.2020 21:37 debian+
Rozbalit Rozbalit vše Re: Změna typu existujících integerů v poli
Bud rad, ze sme nezacali pisat v ASM.

Založit nové vláknoNahoru

Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.