Цель- C в C ++ чтение двоичного файла в многомерный массив с плавающей запятой - PullRequest
4 голосов
/ 09 мая 2020

Я хочу преобразовать следующий код из target C в C ++.

В классе myClass у меня есть этот атрибут:

float tab[dim1][dim2][dim3];

В target- C файла, многомерный массив заполняется из двоичного файла:

NSData *dataTab=[NSData dataWithContentsOfFile:[[NSBundle mainBundle] pathForResource:@"pathOfMyTab" ofType:@""]];
[dataTab getBytes:myClass -> tab  length:[dataTab length]];

Как я мог перевести эту часть на C ++?

Ответы [ 4 ]

1 голос
/ 18 мая 2020

Я предполагаю, что ваш файл содержит байтовое представление массива. Если это так, то для имитации c поведения вашего кода Objective- C с использованием только C ++ (единственное, что делает этот C ++, - это reinterpret_cast<>, в противном случае это просто C), вы можно использовать следующий код. Я не добавлял никаких проверок ошибок, но оставил некоторые комментарии, в которых вы, возможно, захотите выполнить некоторые.

float tab[dim1][dim2][dim3];

CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef dataTabURL = CFBundleCopyResourceURL(mainBundle, CFSTR("pathOfMyTab"), NULL, NULL);

CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, dataTabURL); // check for NULL return value
CFReadStreamOpen(stream);                                              // check for errors here
CFReadStreamRead(stream, reinterpret_cast<UInt8 *>(tab), sizeof tab);  // check that this function returns the number of bytes you were expecting (sizeof tab)
CFReadStreamClose(stream);

// we own "stream" and "dataTabURL" because we obtained these through functions
// with "create" in the name, therefore we must relinquish ownership with CFRelease
CFRelease(stream);
CFRelease(dataTabURL); // ditto

Если у вас уже есть путь, доступный в std::string, вы можете использовать следующий код C ++ чтобы мими c поведение вашего кода Objective- C:

// make sure to include this header
#include <fstream>

// ... then elsewhere in your .cpp file ...
float tab[dim1][dim2][dim3];

std::string path = "path/to/mytab"; // obtain from somewhere
std::ifstream input(path, std::ios::binary); // check that the file was successfully opened
input.read(reinterpret_cast<char *>(tab), sizeof tab); // check that input.gcount() is the number of bytes you expected

Я считаю, что в этом случае мы должны использовать reinterpret_cast<>, потому что файл содержит фактическое представление массива (при условии, что это был ранее записан в файл аналогичным образом).

Вы можете использовать гибридный подход, если у вас есть CFURLRef, содержащий путь к ресурсу, вы можете получить представление URL-адреса в файловой системе, используя эта функция (предоставляющая выходной буфер подходящего размера для хранения результата), и оттуда вы сможете передать это в один из конструкторов std::ifstream (хотя вам может потребоваться приведение к соответствующий тип).

C ++ не поддерживает массивы переменной длины (размер массивов должен быть известен во время компиляции). Стандартной библиотекой также нет типа матрицы, поэтому, если размеры вашей таблицы меняются во время выполнения, вам понадобится совершенно отдельный подход к тому, который был в моем ответе. Вы можете рассмотреть возможность сериализации вывода из Objective- C (используя, например, JSON или другой формат), чтобы размеры матрицы также записывались в вывод, что упрощает синтаксический анализ файла на C ++.

1 голос
/ 09 мая 2020

На мой взгляд, самый простой и быстрый способ - использовать memcpy () для копирования байтов NSData в целевой массив с той же структурой (размерами), что и исходный. См., Например:

https://github.com/Voldemarus/MultiDimensionalArrayDemo/tree/master

#import "DemoClass.h"

#define DIM1    3
#define DIM2    4
#define DIM3    2

@interface DemoClass() {
    int src[DIM1][DIM2][DIM3];  // source (initial) array

    int dst[DIM1][DIM2][DIM3];  // destination array
}
@end

@implementation DemoClass

- (instancetype) init
{
    if (self = [super init]) {
        for (int i = 0; i < DIM1; i++) {
            for (int j = 0; j < DIM2; j++) {
                for (int k = 0; k < DIM3; k++) {
                    int value = i*100 + j*10 + k;
                    src[i][j][k] = value;
                }
            }
        }
    }
    return self;
}

int getIntFromArray(int *array, int i, int j, int k) {
    int offset = j*DIM3 + i*DIM2*DIM3;
    return array[offset];
}

void putIntToArray(int *array, int i, int j, int k, int value) {
    int offset = j*DIM3 + i*DIM2*DIM3;
    array[offset] = value;
}

- (void) run
{
    // Step 1. Save array into NSData
    NSInteger s = sizeof(int)*DIM1*DIM2*DIM3;
    NSData *data = [[NSData alloc] initWithBytes:src length:s];
    NSAssert(data, @"NSData should be created");
    //Step2 - Create new array
    int *bytes = (int *)[data bytes];
    memcpy(dst,bytes,s);
    // Step 3. Compare src and dst
    for (int i = 0; i < DIM1; i++) {
        for (int j = 0; j < DIM2; j++) {
            for (int k = 0; k < DIM3; k++) {
                int template = i*100 + j*10 + k;
                int s = src[i][j][k];
                int d = dst[i][j][k];
 //               NSLog(@"i %d j %d k %d -->s = %d  d = %d",i,j,k,s,d);
                NSAssert(s == template, @"Source array should have value from template");
                NSAssert(d == s, @"Destination array should be identical to the source");
            }
        }
    }

}

@end
1 голос
/ 09 мая 2020

Взгляните на fstream, fread и read, все читаемые двоичные файлы, выберите подходящий подход.

0 голосов
/ 13 мая 2020

float tab[dim1][dim2][dim3] выглядит как трехмерный массив. Стандартная реализация - это три вложенных цикла FOR.

Таким образом, ваша реализация на C ++ может выглядеть так:

  • read dim1, dim2, dim3 откуда-то , обычно первые значения в файле (например, 12 байтов, 4 байта на каждое число)
  • прочтите остальную часть файла в трех вложенных FOR циклах

Что-то вроде:

    for (size_t i = 0; i < dim1; ++i) 
       for (size_t j = 0; j < dim2; ++j)
         for (size_t k = 0; k < dim3; ++k)
           tab[i][j][k] = read_float_value(inputFile);

В Objective- C вы можете записать файл аналогичным образом.

Вот несколько примеров для начала:

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...