Переписать входной файл в выходной в обратном порядке

Здравствуй народ знающий, народ всемогущий.
Решил реализовать такую вот простенькую задачу:

написать консольное приложение, которое получает на вход бинарный файл произвольного размера и в качестве результата создает новый файл, в котором содержимое входного файла записано в обратном порядке (побайтно). Имена входного и выходного файлов должны передаваться через параметры командной строки:
[[
program.exe input.dat output.dat
]]

Например, если на входе файл input.dat в котором записаны байты {0×0A, 0×00, 0×20, 0xFF}, то на выходе должен быть файл output.dat в котором записаны байты {0xFF, 0×20, 0×00, 0×0A}.

Подойдет ли решение для портфолио, и что можно было бы в нем изменить?

main.cpp

#include <iostream>
#include <string>
#include "OFile.h"
#include "IFile.h"
 
using namespace std;
 
int main(int argc, char * argv[]) {
    switch (argc) {
    case 3: {
        OFile OutFile(argv[1]);
        IFile InFile(argv[2]);
        OutFile.Read();
        int size = OutFile.getsize();
        char **buffer = new char *[size];
        for (int i = 0; i < size; i++) {
            buffer[i] = new char[2];
        }
        for (int i = 0; i < size; i++) {
            buffer[i] = OutFile.getbuf(i);
        }
        InFile.Write(buffer, size);
    }
        cout << "THE END!" << endl;
        break; 
    case 2: cout << "Missing 1 argument" << endl; break;
    case 1: cout << "Not arguments" << endl; break;
    default: cout << "Many arguments" << endl; break;
    }
    return 0;
}

XFile.h

#pragma once
#include <iostream>
#include <string>
#include <fstream>
 
using namespace std;
 
class XFile
{
public:
    ~XFile();
    XFile();
protected:
    string FileName;
    /*Установка имени файла, и проверка на существование расширения файла .dat в названии*/
    int CheckFile(char * name);
    /*закрытие файла
    процедуру необходимо перегрузить в производном классе*/
    virtual void CloseFile();
    /*открытие файла
    процедуру необходимо перегрузить в производном классе*/
    virtual int OpenFile();
private:
    /*Проверка расширения файла, 
    если не .dat, программа показывает соответствующее предупреждение и прекращает выполнение*/
    int CheckFileExtansion();
    void SetFileName(char * name);
};

XFile.cpp

#include "XFile.h"
 
XFile::XFile()
{
}
 
XFile::~XFile()
{
}
 
void XFile::SetFileName(char * name)
{
    this->FileName = string(name);
}
 
int XFile::CheckFileExtansion()
{
    string sep = ".";
    string name = FileName;
    string ext;
    size_t pos = 0;
    while ((pos = name.find(sep)) != string::npos) {
        ext = name.substr(0, pos);
        name.erase(0, pos + sep.length());
    }
    if (name == "dat") {
        cout << FileName << ": file extention is correct" << endl;
        return 1;
    }
    else {
        cout << FileName << ": Invalid file extention" << endl;
        exit(10);
    }
}
 
int XFile::CheckFile(char * name)
{
    SetFileName(name);
    CheckFileExtansion();
    return 0;
}
 
void XFile::CloseFile()
{
    cout << FileName<< ": Invalid close file" << endl;
}
 
int XFile::OpenFile()
{
    cout << FileName << ": Invalid open file" << endl;
    return 0;
}

OFile.h

#pragma once
#include "XFile.h"
 
 
class OFile :
    public XFile
{
public:
    /*Чтение всего содержимого файла*/
    void Read();
 
    /*Получение размера файла в байтах (символах)*/
    int getsize();
 
    /*Получение i-ого символа содержимого файла,
    не будет работать до вызова процедуры Read()*/
    char* getbuf(int i);
 
    /*Файл открывается только для чтения,
    Название файла должно быть с расширением .dat,
    файл должен существовать в папке проекта*/
    OFile(char * name);
 
    /*Закрытие файла и очистка буфера*/
    ~OFile();
private:
    char** buffer;
    ifstream file;
    int sizefile;
 
    void CloseFile();
 
    /*Открытие файла только для чтения*/
    int OpenFile();
 
    /*Вычисление размера файла в байтах (символах)*/
    void setsize();
 
    /*Получение кода символа в ASCII в 16-ричной системе счисления,
    результат выводится в виде символьной строки из 2-х символов типа "00"*/
    char* convertChartoHex(char* c, int i);
};

OFile.cpp

#include "OFile.h"
 
void OFile::Read()
{
    file.seekg(0, ios_base::beg);
    buffer = new char * [sizefile]; 
    for (int i = 0; i < sizefile; i++) {
        buffer[i] = new char[2];
    }
    for (int i = 0; i < sizefile; i++) {
        char *c = new char[2];
        file.seekg(i, ios_base::beg); 
        file.read(c, 1);
        c = convertChartoHex(c, i);
        buffer[i][0] = c[0]; 
        buffer[i][1] = c[1];
    }
    cout << FileName << ": Data is read" << endl;
}
 
OFile::OFile(char * name)
{
    CheckFile(name);
    OpenFile();
    setsize();
}
 
OFile::~OFile()
{
    CloseFile();
    for (int i = 0; i < sizefile; i++) {
        delete[]buffer[i];
    }
    delete[]buffer;
}
 
void OFile::CloseFile()
{
    file.close();
    cout << FileName << ": file is closed" << endl;
}
 
int OFile::OpenFile()
{
    file.open(FileName, ios::binary | ios::in);
    if (!file) {
        cout << FileName<< ": Open file - Failed" << endl;
        exit(20);
    }
    else {
        cout << FileName << ": file is opened" << endl;
    }
    return 0;
}
 
void OFile::setsize()
{
    file.seekg(0, ios_base::end);
    sizefile = file.tellg();
    file.seekg(0, ios_base::beg);
    if (sizefile == -1){
        cout << FileName<< ": Invalid size of file" << endl;
        exit(50);
    }
}
 
int OFile::getsize()
{
        return sizefile;
}
 
char * OFile::getbuf(int i)
{
    return buffer[i];
}
 
char* OFile::convertChartoHex(char * c, int i)
{
    int a = c[0];
    int k = 0; 
    char m[2] = {0,0};
    int l = 0;
    while (l != 2) {
        k = a % 16;
        a = a / 16;
        switch (k)
        {
        case 0:  m[l] = '0'; break;
        case 1:  m[l] = '1'; break;
        case 2:  m[l] = '2'; break;
        case 3:  m[l] = '3'; break;
        case 4:  m[l] = '4'; break;
        case 5:  m[l] = '5'; break;
        case 6:  m[l] = '6'; break;
        case 7:  m[l] = '7'; break;
        case 8:  m[l] = '8'; break;
        case 9:  m[l] = '9'; break;
        case 10:  m[l] = 'a'; break;
        case 11:  m[l] = 'b'; break;
        case 12:  m[l] = 'c'; break;
        case 13:  m[l] = 'd'; break;
        case 14:  m[l] = 'e'; break;
        case 15:  m[l] = 'f'; break;
        }
        l++;
    }
    char n = m[0];
    m[0] = m[1];
    m[1] = n;
    return m;
}

IFile.h

#pragma once
#include "XFile.h"
class IFile :
    public XFile
{
public:
    /*Запись содержимого buffer в файл,
    size указывает на размер buffer*/
    void Write(char** buffer, int size);
 
    /*Файл открывается только для записи,
    Название файла должно быть с расширением .dat,
    если файла нет, он создастся,
    если файл существует, он перезапишется*/
    IFile(char * name);
 
    /*Закрытие файла*/
    ~IFile();
private:
    ofstream file;
    void CloseFile();
    int OpenFile();
 
    /*Вычисление символа из 16-ичной системы счисления согласно таблице ASCII,
    на вход подается строка из 2-х символов типа "00", должны присутствовать только цифры и буквы a,b,c,d,e,f
    результат выводится в виде 1-го символа*/
    char convertHextoChar(char* c);
};

IFile.cpp

#include "IFile.h"
 
void IFile::Write(char** buffer, int size)
{
    char *c = new char [size];
    for (int i = size-1; i >= 0; i--) {
        c[size -1 - i] = convertHextoChar(buffer[i]);
    }
    file.write(c, size);
    cout << FileName << ": Data was written" << endl;
}
 
IFile::IFile(char * name)
{
    CheckFile(name);
    OpenFile();
}
 
IFile::~IFile()
{
    CloseFile();
}
 
void IFile::CloseFile()
{
    file.close();
    cout << FileName << ": file is closed" << endl;
}
 
int IFile::OpenFile()
{
    file.open(FileName, ios::binary | ios::out);
    if (!file) {
        cout << FileName << ": Open file - Failed" << endl;
        exit(20);
    }
    else {
        cout << FileName << ": file is opened" << endl;
    }
    return 0;
}
 
char IFile::convertHextoChar(char * c)
{
    int number[2];
    switch (c[0]) {
    case '0': number[0] = 0; break;
    case '1': number[0] = 1; break;
    case '2': number[0] = 2; break;
    case '3': number[0] = 3; break;
    case '4': number[0] = 4; break;
    case '5': number[0] = 5; break;
    case '6': number[0] = 6; break;
    case '7': number[0] = 7; break;
    case '8': number[0] = 8; break;
    case '9': number[0] = 9; break;
    case 'a': number[0] = 10; break;
    case 'b': number[0] = 11; break;
    case 'c': number[0] = 12; break;
    case 'd': number[0] = 13; break;
    case 'e': number[0] = 14; break;
    case 'f': number[0] = 15; break;
    }
    switch (c[1]) {
    case '0': number[1] = 0; break;
    case '1': number[1] = 1; break;
    case '2': number[1] = 2; break;
    case '3': number[1] = 3; break;
    case '4': number[1] = 4; break;
    case '5': number[1] = 5; break;
    case '6': number[1] = 6; break;
    case '7': number[1] = 7; break;
    case '8': number[1] = 8; break;
    case '9': number[1] = 9; break;
    case 'a': number[1] = 10; break;
    case 'b': number[1] = 11; break;
    case 'c': number[1] = 12; break;
    case 'd': number[1] = 13; break;
    case 'e': number[1] = 14; break;
    case 'f': number[1] = 15; break;
    }
    int res = number[0] * 16 + number[1];
    char sim = (char)res;
    return sim;
}
👍ПодобаєтьсяСподобалось0
До обраногоВ обраному0
LinkedIn

Найкращі коментарі пропустити

У Вас явно забагато коду. Те що так можна по швидкому згавняти і воно більш-менш робитиме те що треба, виглядає якось так:

#include<fstream>

int main(int argc, char * argv[])
{
    std::ifstream file_in(argv[1], std::ios::binary);
    std::ofstream file_out(argv[2], std::ios::binary);
    file_in.seekg(-1, std::ios::end);
    for (char ch; file_in.get(ch); file_in.seekg(-2, std::ios::cur))
        file_out << ch;
    return 0;
}
Навіть якщо цей код обв’язати з усіх сторін перевірками на кількість аргументів, існування вхідного файлу, чи не перетираємо ми щось на виході, ітд ітп, до такого монструозного розміру воно не виросте. Навіть якщо додати буферизацію і якось визначати оптимальний розмір буфера, все одно так не виросте. Моя думка, якщо у Вас стільки коду — Ви щось робите не те, або не договорюєте умови задачі.

Та не, решение не серьезное. «файл произвольного размера» — это значит что может быть файл в 10Гб. Ты его читаешь весь в память, еще и буфер второй создаешь для него. А convertChartoHex для чего если файл в бинарном формате? На вскидку я бы ожидал такое решение — в цикле читаем входной файл блоками, например по 4к байт (и храним в памяти только 1 текущий блок, а не все), с конца в начало. Затем инвертируем вычитанный блок и пишем/добавляем его в выходной файл, все.

Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter
Дозволені теги: blockquote, a, pre, code, ul, ol, li, b, i, del.
Ctrl + Enter

Ребята посоветуйте с чего начать самообучение программированию .Цель -создавать сайты.Вообще ничего не знаю и не смыслю , буду очень благодарен за направление на путь истинный. Посоветуете литературу и в какой очередности начать изучение. Спасибо.

case 2: cout << "Missing 1 argument" << endl; break;
case 1: cout << "Not arguments" << endl; break;
default: cout << "Many arguments" << endl; break;
Мені ще сподобалася англійська. Така ще, с тяжким прідихаєнієм, сопєнієм і жуткім рашн акцентом, як ото в Долині на телефонних кодінгових інтерв’ю.

кто короче?
python3 -c ’import mmap;from sys import argv;w=open(argv[2],"wb");r=open(argv[1],"rb");m=mmap.mmap(r.fileno(),0,access=mmap.ACCESS_READ);w.write(m[::-1]);w.close();’ in.bin out.bin

то не считается, там используют уже скомпиленый бинарь для инвертации файлов, а не сырцы. Исходник не такой уж маленький github.com/...​ils/blob/master/src/tac.c

тогда нужно на асме решение написать

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

У мене колись була задача «Є файл в 10 Гб, потрібно видалити з нього перший байт.». Ну тобто отримати файл розміром 10ГБ мінус 1 байт з ідентичним контентом (крім першого байту). І от ніяк цю задачу (як мінімум на Windows + NTFS) не можна вирішити без повного читання і повного (без одного байту) запису 10 Гб даних.

Не важливо, чим видаляти. Важливо, що операція запису файлу після цього прочитає і запише 10 Гб даних.

ntfs ацтой и не поддерживает неполные сектора

тобто там не можна було зробити маніпуляцію із одним — двома секторами, замість перетирання всього-всього?

можна але не можна змінити розмір даних у окремому секторі окрім останнього ))

та ні, виходить не можна, так як тре дані у всіх секторах зсувати на байт
або зробити «сектор настандартної довжини» (хз. чи можливо)

а аби можна було тоді можна було би «посунути» лише 1 сектор переписавши лише його чистий профітЪ!

ЗЫ: доречі це проста але певно неочевидна штука і з цього легко і очевидно виходить чому архітектура БД заснована на принципі «завжди дописувати в кінець» замість «змінювати дані за місцем де були».

Автор вбросил и пошёл :)

Так напишите ему в LinkedIn или на Скайп. :)

В этом коде совсем все плохо. Начиная от архитектуры, выбранного подхода, заканчивая опечатками. Код раздут искусственно, и огромные switch выглядят ужасно.
Но нет ничего плохого в ошибках. Советую удалить полностью ваш код, как промежуточный опыт, прослушать лекции, либо прочитать умные статьи по с++, и попытаться написать все сначала.

Советы:
Читать и писать файл нужно блоками, работу с hex вам не нужно писать руками, есть уже готовые для этого функции. Удалить convertHextoChar как страшный сон. Почитать умные статьи по ООП. Но конкретно в этой задаче, вам не нужны все эти классы, не нужно наследование, не нужно писать лишний код даже для портфолио.

Як щодо написати файлову систему де у властивостях файлу можна буде вказати що його треба читати у зворотньому порядку? Оце був би хороший проект для портфоліо!

Можна ще написать драйвера для жорсткого диску, щоб він його в зворотньому напрямку розкручував.

Ну, как я понял, автор топика не ищет легких путей, так что должно подойти.

Спасибо, поржал =)

program.exe input.dat output.dat
...
OFile OutFile(argv[1]);
IFile InFile(argv[2]);
OutFile.Read();
InFile.Write(buffer, size);

А обозвать input.dat OutFile (и читать из OutFile), а output.dat InFile (и писать в него) — это специально, чтобы врагу жизнь усложнить? :-)))

void XFile::SetFileName(char * name)
{
    this->FileName = string(name);
}

Честно говоря мне одного этого метода хватит, чтобы вас не брать на плюсы:

* Почему тривиальная функция реализована не в заголовке? (Ломает инлайнинг-оптимизацию)
* Зачем «this->», если мы и так в теле метода класса?
* Почему не «const char», менять в процессе работы будете?
* Почему бы не принимать «const string&» получив бонусом инициализацию что от string, что от const char*?

Вы уверены, что при современном компиляторе оптимизация поломается из-за определения функции в хедере? (и если нет, то зачем загрязнять хедер реализациями?)

* Почему тривиальная функция реализована не в заголовке? (Ломает инлайнинг-оптимизацию)

А почему она обязана быть реализована в заголовке?
«(Ломает инлайнинг-оптимизацию)» — это привет из нулевых.

* Зачем «this->», если мы и так в теле метода класса?

Для наглядности. Вопрос стиля, это не ошибка.

* Почему бы не принимать «const string&» получив бонусом инициализацию что от string, что от const char*?

И выполнять лишние аллокации каждый раз при аргументах типа const char* или rvalue стрингах (:
Если уж на то пошло, то лучше принять std::string по значению и присвоить через std::move.
Хотя и это спорно. В книге Майерса были расписаны за и против для такого подхода, как раз на примере со стрингами.

А почему она обязана быть реализована в заголовке?
«(Ломает инлайнинг-оптимизацию)» — это привет из нулевых.

А что, lto в gcc допилили? Им уже можно пользоваться, небоясь получить кривой бинарь?

Для наглядности. Вопрос стиля, это не ошибка.

Смешивать табы и спейсы — тоже вопрос стиля. (На самом деле, табы — отстой, спейсы рулят)

совсем недавно видел обсуждение лто. как раз в гцц оно работает гораздо лучше, чем в силанге

хз. это по словам инжинеров интел

А что, lto в gcc допилили? Им уже можно пользоваться, небоясь получить кривой бинарь?

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

Смешивать табы и спейсы — тоже вопрос стиля.

Смешивать табы и спейсы — вопрос говнокода. А что-то одно из этого юзать (что именно?) — да, вопрос стиля.

(На самом деле, табы — отстой, спейсы рулят)

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

«(Ломает инлайнинг-оптимизацию)» — это привет из нулевых.

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

Для наглядности. Вопрос стиля, это не ошибка.

Учитывая, что в соседнем же методе без this, а писал один и тот же человек, наталкивает на сомнения, что он понимает, зачем это.

И выполнять лишние аллокации каждый раз при аргументах типа const char* или rvalue стрингах (:

Да ващет нет, атрибут класса же std::string, какая разница где происходит его инициализация, неявно в вызове или явно в присваивании? Там и так, и так будет вызов одного конструктора, только в оригинальном варианте std::string придется явно преобразовывать к const char* (который без const вообще все повалит).

Самопочин: инициализация значения при присваивании, а не самого аттрибута.

Учитывая, что в соседнем же методе без this, а писал один и тот же человек, наталкивает на сомнения, что он понимает, зачем это.

Это уже другой вопрос. С этим я и не спорил.

Да ващет нет

Ещё раз. Допустим, функция принимает const std::string&. На стороне вызова передали const char* (или rvalue std::string) — сконструировался темповый стринг — это первая аллокация. Затем этот темповый стринг копи ассайнментом (а не мув ассайнментом!) присвоился полю класса — и это потенциально вторая аллокация.
А могли бы после первой аллокации мувнуть темповый объект прямо в поле класса.

А могли бы после первой аллокации мувнуть темповый объект прямо в поле класса.

И поскольку аллокаций нет, то можно пометить метод как noexcept.

Это скользкий момент. Саттер об этом говорил. Типа, «по закону»-то оно так. Но «по совести» лучше так не делать.
Ведь внутри самой функции эксепшен действительно невозможен — но вот в месте её вызова (при создании стринга) он всё ещё может вылететь. А тут мы такие со своим ноэксептом как бы говорим юзеру: «ха-ха, затроллен! у меня эксепшенов нет, но ты его получил ещё до того, как добрался ко мне, так что это твои проблемы, лул!»

Сразу после процессора

На шарпе ровно три строчки кода.
Прочитать файл в массив, вызвать массиву реверс, записать массив в файл.

Если большой файл не влазит в ОЗУ, с оптимизацией будет 5-10 строчек кода.

Ориентируйся на этот объем кода.

На шарпе ровно три строчки кода.
Прочитать файл в массив, вызвать массиву реверс, записать массив в файл.

На плюсах тоже:

#include <fstream>
#include <vector>
#include <algorithm>

using namespace std;

int main(int argc, char** argv)
{
  ifstream file_in {argv[1], ios::in  | ios::binary};
  ofstream file_out{argv[2], ios::out | ios::binary};

  vector<char> data{istreambuf_iterator<char>{file_in}, istreambuf_iterator<char>{}};
  reverse(data.begin(), data.end());

  copy(data.begin(), data.end(), ostreambuf_iterator<char>{file_out});
}

(ну ладно, не три, а пять)

(ну ладно, не три, а пять)

=>

int main(int argc, char** argv)
{
  vector<char> data{istreambuf_iterator<char>{*(make_unique<ifstream>(argv[1], ios::in  | ios::binary))}, istreambuf_iterator<char>{}};
  reverse(data.begin(), data.end());

  copy(data.begin(), data.end(), ostreambuf_iterator<char>{*(make_unique<ofstream>(argv[2], ios::out | ios::binary))});
}

ЗЫ: кстати не работает с utf8 ((

Слишком нечитабельно уже получается, как по мне :(
Да и динамические аллокации для фстримов лишние, если можно их создать на стеке. Хотя и современные компиляторы с поддержкой C++14 имеют право оптимизировать такого рода аллокации, заменяя их на стековые.

Я ещё сначала подумал переписать так:

  vector<char> data{ istreambuf_iterator<char>{ifstream{argv[1], ios::in | ios::binary}}, istreambuf_iterator<char>{} };
  reverse(data.begin(), data.end());
  copy(data.begin(), data.end(), ostreambuf_iterator<char>{ofstream{argv[2], ios::out | ios::binary}});
— но потом увидел, что у istreambuf_iterator’а конструктор принимает не-const ссылку на istream, посему привязать временный объект (не используя нестандартные расширения некоторых компиляторов) к ней не получится.
кстати не работает с utf8 ((

Так задачка ведь про бинарные файлы.

тоді чому ітератор по char-у?

Насправді це питання більш глибоке, ніж можна подумати на перший погляд :)

Дійсно, в плюсах довгий час типи char або unsigned char були синонімами байта. І старі фічі стандартної бібліотеки (такі як iostream’и/fstream’и) працюють з байтами через тип char*.

Проте в стандарті С++17 комітет нарешті стандартизував новий тип std::byte як окрему безпечну альтернативу цьому легасі, без зайвих можливостей та дурної назви («char» має означати символ, а по факту означає байт — фігня якась). І в нинішніх реаліях хотілося б використовувати std::byte замість чарів.

Проблема в тому, що фстріми все ще не готові до роботи з байтами. Вони гвіздками прибиті до «символьних» типів — тобто таких типів, для яких існує спеціалізація шаблону std::char_traits.
Для типу std::byte її, очевидно, немає — байт же не символ.
Фічі з нещодавно стандартизованої filesystem самі по собі не дозволяють відкрити файл і прочитати з нього байти — тут все ще потрібно використовувати фстріми.

Проблему можна обійти, написавши власні «char_traits» для байта.
Якщо подивитися на вимоги до чар_трейтів (en.cppreference.com/w/cpp/string/char_traits), можна зрозуміти, що, незважаючи на назву, для байта там майже все має сенс (крім функції length).

Маючи реалізацію таких std_byte_char_traits, легко створити аліаси для потрібних нам стрімів та ітераторів, які використовуватимуть тип std::byte замість чарів:

using byte_istreambuf_iterator = std::istreambuf_iterator<std::byte, std_byte_char_traits>;
using byte_ostreambuf_iterator = std::ostreambuf_iterator<std::byte, std_byte_char_traits>;

using byte_ifstream = std::basic_ifstream<std::byte, std_byte_char_traits>;
using byte_ofstream = std::basic_ofstream<std::byte, std_byte_char_traits>;

І тоді мій код можна буде переписати наступним чином:

int main(int argc, char** argv)
{
  byte_ifstream file_in { argv[1], ios::in  | ios::binary };
  byte_ofstream file_out{ argv[2], ios::out | ios::binary };

  vector<byte> data{ byte_istreambuf_iterator{file_in}, byte_istreambuf_iterator{} };
  reverse(data.begin(), data.end());

  copy(data.begin(), data.end(), byte_ostreambuf_iterator{file_out});
}

Шкода, що комітет зі стандартизації плюсів разом з введенням std::byte не придумав чогось подібного в стандарті, щоб люди нарешті перестали обзивати байти «чарами» в реальному коді.

Слишком нечитабельно уже получается, как по мне :(

бидняшко ((

Ну, как бы для меня тоже «читабельно» в плане того, что я могу такой код прочитать и понять, что он делает. Но всё ещё код выглядит излишне сложным при таком написании в одну строчку.

Я не про длину строки, а про количество действий, выполняемых в пределах одной строчки.
Динамически создаём фстрим, завёрнутый в юник_птр, разыменовываем этот юник_птр и передаём ссылку в конструктор для создания стримбуф_итератора, затем передаём получившийся итератор (вместе с ещё одним, дефолтно сконструированным) в конструктор создаваемого в этой же строчке вектора... Ну, такое.

я не знаю що учать в СХХ, але в ембедед місра рулз рекомендує «одна строка одна дія»,
а дебажити СХХ код, та ще в такому стилі ... для БДСМ збоченців

я не знаю що учать в СХХ, але в ембедед місра рулз рекомендує «одна строка одна дія»,

В плюсах нормою є код виду

vector<char> data{istreambuf_iterator<char>{file_in}, istreambuf_iterator<char>{}};

Не буквально одна дія на рядок, але створення цих ітераторів надто тривіальне, щоб мало сенс його виносити в окремі рядки. Тому вийшло щось типу «один рядок — одна суттєва дія».

Розносити такий рядок на ще більш елементарні

istreambuf_iterator<char> iter_begin{file_in};
istreambuf_iterator<char> iter_end;
vector<char> data{iter_begin, iter_end};
сенсу немає.

Хоча я мало знаю про застосування плюсів саме в ембедеді. Плюси це ж мова, а ембедед — напрям. Закономірно, що напрям і специфіка проекту можуть нав’язувати свої обмеження на використання мови. Так що, можливо, в ембедед-плюсах таке і потрібно, якщо там, наприклад, надто незручно дебажитись без подібного розділення.

а дебажити СХХ код, та ще в такому стилі ... для БДСМ збоченців

Без IDE — мабуть, так. Я працюю переважно в мєлкомягкій студії або кьюткреаторі, там код в такому стилі дебажити не набагато важче, ніж розділений на більш атомарні шматки.
А от читати подібне все одно неприємненько. Власне, в цьому і була моя претензія до прикладу Алекса.

Кстати да вот и пример на ту же ж тему причём с тем же исходным контекстом только мне пришлось придумать заюзать что-то стандартное чтобы уложиться в исходные «три строчки а не пять».

gist.github.com/...​itum/f2567b7f263d4f6c7691

Очень опасный подход, который может легко приводить к висячим ссылкам при малейшей неосторожности. Не одобряю :(

Сначала я вообще подумал, что здесь UB, т.к. функция lvalue() возвращает висячую ссылку. Типа, временный объект привязался к параметру r, этот r вышел из скоупа, а его возвращённая копия жизнь не продлевает, приехали.
Потом уже вспомнил про особенные правила для сиквенс поинтов (или как там оно сейчас правильно называется). На пальцах: если до ближайшей точки с запятой в строке, где создаётся временный объект, мы ещё не дошли, то объект преждевременно умереть не должен.
Это всё крайне неочевидно.

вот вам смешно а на продакшине падаваны продактят такой код... ))

це не падаван, це уже личинка мідла!

я их не различаю считаю подряд ((

вообщето пацан іде к успєху,
от напишеш С варіант в стилі KISS, манахер гляне і скаже, пля як просто, я і сам так моху накуячить за 20 мінут.

а тут пля, не сходу в"їдеш.... там мемлік, там креш, тре уніт-тести...
можна продать 40 манкі-часов... всім профіт.

даже стаття була про щось подібне, толі на хабрі толі ще де...

а тут пля, не сходу в"їдеш.... там мемлік, там креш, тре уніт-тести...
можна продать 40 манкі-часов... всім профіт.

це звэться solution architect (к) (тм)

даже стаття була про щось подібне, толі на хабрі толі ще де...

dou.ua/forums/topic/19756
dou.ua/...​uct-without-simple-tasks
...

не про то, а про умовного Алана і Джона,
один педалив KISS другий якуць куєту із художньою різьбою...
перший вилетів нах (дуже банальний код), другий зробив кар"єру (да-да, тянув на солюшен архітекта)...

а нечего нанимать только начавших изучать программирование студентов, которые даже на трейни не тянут, на позицию джуна :(

да-да-да я эту поучительную историю в среднем слышу через раз но в последнем время всё чаще ))

модератори, можна перейменувати тему в
«ЦеПеПе: дно пробито»

ЦеПеПе

Ну да, ведь на других языках такого кода не напишешь.

И это не «пробитие дна». Это типичный код первокурсника, который только начал изучать программирование. Все с чего-то такого начинали.
Другое дело, что если чувак пишет такой код и при этом позиционирует себя как junior developer’а, то это печально.

Это типичный код первокурсника,

у ТС в профиле есть ссылка на линкедин, где написано что он «Окончил СПбГУАП по направлению Информатика и вычислительная техника». Либо у них там за поребриком все настолько плохо с обучением, либо ТС тролль

почитай
www.drdobbs.com/...​arne-stroustrup/207000124

James: When you created C++, was the object oriented programming (OOP) paradigm (or programming style) obviously going to gain a lot of popularity in the future, or was it a research project to find out if OOP would catch on?

Bjarne: Neither! My firm impression (at the time) was that all sensible people „knew” that OOP didn’t work in the real world: It was too slow (by more than an order of magnitude), far too difficult for programmers to use, didn’t apply to real-world problems, and couldn’t interact with all the rest of the code needed in a system. Actually, I’m probably being too optimistic here: „sensible people” had never heard of OOP and didn’t want to hear about it.

...

Conversely, there is now a generation who is firmly convinced that a program is only well-designed if just about everything is part of a class hierarchy and just about every decision is delayed to run-time. Obviously programs written by these „true OO” programmers become the best arguments for the „stick to C” programmers.

так отож, „нове покоління ООП ООД прогерів пробиває дно”

хорошо, что на русте подобное невозможно

руст не дуже ООП ООД френдлі,
думаю, щоп друканути Хелло Ворлд, класс создавать не нада
fn main() {
println!("Hello World!");
}

думаю, щоп друканути Хелло Ворлд, класс создавать не нада

а в плюсах нада?

Тарас, ти пробиваєш дно

#include
using namespace std;

int main()
{
cout << „Hello, World!”;
return 0;
}

www.cplusplus.com/reference/iostream/cout
Standard output stream
Object of class ostream that represents the standard output stream oriented to narrow characters (of type char). It corresponds to the C stream stdout.

чи ти будеш прінтефом, але це тупе Це (не ЦеПеПе) !!!

И где тут «создание класса»?

плюсовиками пробито дно донне (Сішник знає ЦеПеПе краще ЦеПеПЕ синйора):
RTFM

cout
Standard output stream
Object of class ostream that represents the standard output stream

Що в перекладі: об«єкт КЛАССА!!!!!

И где тут «создание класса»

в STLі, чи де?

пробито дно донне:

Тобою. Вже двічі.

Object of class ostream that represents the standard output stream

І хто його створює? Ми?

якщо є клас, то хтось його створив

Ну да, рантайм його створив при запуску програми, до початку виконання нашого коду. Програміст не пише ні слова специфічно для створення цього об’єкта.

а може компілєр тайм (копаєм дно далі..)?

а може компілєр тайм

Учі матчасть, сказано ж тобі.
en.cppreference.com/w/cpp/io/cout
en.cppreference.com/w/cpp/io/ios_base/Init

копаєм дно далі..

Копай, у тебе добре виходить. «Джава лайно бо там щоб вивести хеллоуворлд треба запустити гарбаджколлектор» — логіка уровня ембеддед експєрта.

о, крім наїздів на нік нейм, пішло передьоргування

Це не передьоргування. Це така ж логіка, як твоє «створення класу». Я просто подумав, що на прикладі з чимось, що ти не ненавидиш так люто-бєшено, як плюси, тобі стане зрозумілішою абсурдність подібних заяв.
Джавісти не піднімають ручками гарбадж коллектор в своєму хеллоуворлді. Як і плюсовики не створюють глобальних об’єктів зі стандартної бібліотеки. Це робота рантайма. Аналогія достатньо вдала, по-моєму.

Потрібно використовувати дефолтний об’єкт і потрібно такий об’єкт створювати (або, тим більше, створювати клас) — дві великі різниці.
Якби ти написав зразу про використання, тут би не було про що спорити.
А так вийшло, що передьорнув як раз ти, коли спочатку написав про одне, а потім перевів тему на інше.

, що ти не ненавидиш так люто-бєшено, як плюси,

откуда ти взяв, навпаки,
Слава ЦеПеПе!
Воно створює безкінечну зайнятість в індустрії, так як те що можна було зробити за день і забути, можна бадяжити місяцями!

Воно створює безкінечну зайнятість в індустрії, так як те що можна було зробити за день і забути, можна бадяжити місяцями!

Ну коли знання девелоперів у команді на рівні «для написання хеллоуворлда потрібно створювати клас», то канєшно так воно і буде.

передьорнув як раз ти

эсли бы только он просто передергивал, вместо того, чтобы тут писать хейт посты

Я — ні. А от ти, флюман, тепер офіційно пробив дно, побачивши створення класу там, де його немає. Тут немає навіть створення об’єкта класу. Учі матчасть.

www.cplusplus.com/reference/iostream/cout
Standard output stream
Object of class ostream that represents the standard output stream

так що, брешуть?

флюман

сліфф зощітан

Не брешуть. Це дійсно об’єкт, так.
І це ніяк не суперечить тому, що ми цей об’єкт не створюємо.

Чи ти рахуєш ще й те, що відбувається «під капотом» на старті? Тоді одним створенням об’єктів не обійтися. Треба ще поскаржитися, наприклад, на лінковку з бібліотеками ОС, щоб цей хеллоуворлд взагалі вивівся на екран.

мова йшла про те, що для хеловорд в ЦеПеПе не тре використовувати класи
===
Taras Morozovsky
час назад

>> думаю, щоп друканути Хелло Ворлд, класс создавать не нада

а в плюсах нада?

класс создавать не нада
создавать
создавать

=>

мова йшла про те, що для хеловорд в ЦеПеПе не тре використовувати класи
використовувати

Пробиваємо дно далі ;)

замість бикування, ти міг би визнати помилку, і сказати «дякую», за те, що зменшив рівень твого невідання

Я не бикував — я спростував твої слова, коли ти написав неправильне твердження про необхідність «створювати клас».
Вибач, якщо мій тон здався надто різким. Але ти сам провокуєш таке відношення до себе своїм «невіданням» вкупі з зашкалюючою впевненістю у своїй правоті (коли насправді ти неправий).

Почекайте, давайте без емоцій.

Між СТВОРЮВАТИ клас та ІНСТАНЦІЮВАТИ об’єкт класу є різниця все ж таки. До того ж в приведеному прикладі навіть інстанціювання не відбувається, там ВИКОРИСТАННЯ об’єкту натомість.

Так, клас цей був кимось колись написаний, але він є частиною бібліотеки яка в свою чергу є частиною С++. Тому і в приведеному прикладі нема СТВОРЕННЯ класу.

Ооо, меряние хелловорлдами, смотрю, очень популярная забава

that OOP didn’t work in the real world

А-а-а-а-а... Сльози щастя на очах! Я не один такий!

Читав. І до чого тут це? На джаві, шарпі і інших мовах з ООП не можна написати кривий гавнокод? Плюси, до речі, як раз не нав’язують ОО-парадигму.
Чи, може, в сішній структурній/процедурній манері написання коду подібної якості неможливо?

І при чому тут нове покоління? Ти серйозно вважаєш, що справа в «поколінні», а не знаннях і досвіді конкретної людини?

це ще автор ЦеПеПе так вважає

Не знаю, що ти там вже «між рядками» у нього прочитав.

На джаві, шарпі і інших мовах з ООП не можна написати кривий гавнокод?

Пля,,,
нафига я начал смотреть код после main.cpp.
... пойду напьюся.

Для портфолио (или как его там) точно не сгодится.

...Как минимум, вот тут утечка памяти будет.

        for (int i = 0; i < size; i++) {
            buffer[i] = new char[2];
        }
        for (int i = 0; i < size; i++) {
            buffer[i] = OutFile.getbuf(i);
        }

Я канєшна дико извиняюсь, но Вы успели дочитать учебник до раздела Массивы ? И примкну к предыдущим товарищам: зря Вы пропустили раздел «С».

Ответы на Ваши вопросы: нет, все.

как то так....
#tac [input] | tac > [reverse_input] && chmod u+x [reverse_input]

#tac [input] | tac > [reverse_input] && chmod u+x [reverse_input]

по-перше, „не так”, а „cat”
напевне, хотіли написати
cat [input] | tac > [reverse_input] && chmod u+x [reverse_input]

по-друге
Useless Use of Cat Award
porkmail.org/era/unix/award.html
і достатньо
tac [input] > [reverse_input] && chmod u+x [reverse_input]

омойбог. А что если это просто троллинг?

і заради нього наваять тонни говнокода

где ж тонны, это же не физбаз энтерпрайз эдишн

ладно, переконав, ТС — троль і правічєк

На конкурс «самое сложное решение» подойдет однозначно.

        switch (k)
        {
        case 0:  m[l] = '0'; break;
        case 1:  m[l] = '1'; break;
        case 2:  m[l] = '2'; break;
        case 3:  m[l] = '3'; break;
        case 4:  m[l] = '4'; break;
        case 5:  m[l] = '5'; break;
        case 6:  m[l] = '6'; break;
        case 7:  m[l] = '7'; break;
        case 8:  m[l] = '8'; break;
        case 9:  m[l] = '9'; break;
        case 10:  m[l] = 'a'; break;
        case 11:  m[l] = 'b'; break;
        case 12:  m[l] = 'c'; break;
        case 13:  m[l] = 'd'; break;
        case 14:  m[l] = 'e'; break;
        case 15:  m[l] = 'f'; break;
        }
m[l]=’0’+k;
И комменты надо отсекать символами // , не /* , потому как в дальнейшем будет сложно закомментить большой кусок.

Міняти стиль коментарів із сі-сумісного на інший чисто тому що хтось захоче відкоментити цей код? Хай коментять із #if 0 #endif

В чем прикол С-совместимых комментариев в спп файле?

сі-сумісного

Интересно, а существует ли еще компиляторы, которые не умеют в плюсовые комментарии в си коде (как экстеншн)?

Вижуал студия 2010 не умеет C99, но умеет однострочные комменты в си-коде, например.

На цьому шматку спіткнувся на промотці, коли дивився, чи є тут щось крім коду. Це змусило подивитись, що взагалі за код.

потому как в дальнейшем будет сложно закомментить большой кусок.
#if 0
....
#endif

Спасибо что вернули меня в школьные годы далеких 90х ))

Из полезного автору могу посоветовать почитать это: rozetka.com.ua/22024857/p22024857 и это www.livelib.ru/...​hih-programm-skott-mejers

ну тоді вже точно Ктулху фхтагн

та нє, якраз Ктулху з FAANG зараз кудись пропав. а я ще лиш хотів йому натякнути, що він надутий індик (dou.ua/...​rums/topic/26018/#1488002 ).

У Вас явно забагато коду. Те що так можна по швидкому згавняти і воно більш-менш робитиме те що треба, виглядає якось так:

#include<fstream>

int main(int argc, char * argv[])
{
    std::ifstream file_in(argv[1], std::ios::binary);
    std::ofstream file_out(argv[2], std::ios::binary);
    file_in.seekg(-1, std::ios::end);
    for (char ch; file_in.get(ch); file_in.seekg(-2, std::ios::cur))
        file_out << ch;
    return 0;
}
Навіть якщо цей код обв’язати з усіх сторін перевірками на кількість аргументів, існування вхідного файлу, чи не перетираємо ми щось на виході, ітд ітп, до такого монструозного розміру воно не виросте. Навіть якщо додати буферизацію і якось визначати оптимальний розмір буфера, все одно так не виросте. Моя думка, якщо у Вас стільки коду — Ви щось робите не те, або не договорюєте умови задачі.

Кстати, seek() - это может быть очень дорогая операция. Иногда будет выгоднее делать seek() выходного файла, а не входного. Например, на DVD seek() может вызвать прокручивание диска до наведения на нужную дорожку. С другой стороны, seek() выходного файла будет вынужден делать форсированную выгрузку буфера, поэтому писать определенно надо блоками.

То вже треба дивитись по ситуації, я чисто базову версію на коліні прикинув, яка вирішує задачу.

Якщо вже щось дуже оптимізувати, то я би в першу чергу дивився, що там з викликами функцій і чи може компілятор нормально все вінлайнити, а чи таки треба переписувати для мінімізації викликів.

За головки-циліндри я би вже в останню чергу думав, бо як мінімум потоки в С++ буферизують, потім, швидше за все, зверху буде якась ОС з драйверами — там на кожен чих буферизація, а навіть як і дійде до того вінчестера, то там купу якоїсь розумної електроніки напаяно і я навіть не впевнений, чи ті сектори і циліндри, що ми бачимо з ОС, хоч якось відповідають фізичній картині всередині, чи то все «віртуальна реальність» (може хто знається цей момент прокоментує, мені було б цікаво). плюс, там точно буде свій кеш і якісь алгоритми, які передбачатимуть що я там далі захочу читати-писати і якось будуть під те діло підлаштовуватись.

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

char m[2] = {0,0};
....
return m;

возвращать указатель на стеке — это писец, а не портфолио.

это крэш, Карл!

там еще и потеря памяти

И вообще)

страшная болезнь. ты к доктору обращался?

ти дизайн і код дивився і тебе влаштовує.
на С (без класів) було достатньо читати в циклі побайтно з кінця один файл і записувати в другий
але на С++, як завжди, вийшла порно похабщина

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

проблема в тому, що потім такі от приплюснуті якимось дивом потім попадають на ембедед проект і начинають рулити ембедедом. ось в чому проблема

ну так по рукам надо давать. думаешь, начинающий rustаман лучше пишет?

дивлячись з чого начинающий, якщо після С, то одне, якщо після уеба, то інше, а вайтішнік, навряд чи руст осилить з нуля

А хто їм дозволяє там рулити? Я не уявляю, як треба проводити співбесіди, щоб не відсіяти людей, які програмують на такому рівні. Причому це абсолютно ніяк не залежить від мови чи напрямку розробки: написати дико ускладнене роздуте нєчто з купою багів можна і на сях, і на джаві, і на чому завгодно.

Да, интересная болезнь. Когда пациент видит вину плюсов и плюсовиков в любой ситуации, где что-то не в порядке и где хоть как-то упоминаются плюсы. Он на доу при каждом удобном случае такие комментарии оставляет уже который год.

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

Портфолио? Сделай репо на гитхабе. Заодно не надо будет постить сюда текст.

Та не, решение не серьезное. «файл произвольного размера» — это значит что может быть файл в 10Гб. Ты его читаешь весь в память, еще и буфер второй создаешь для него. А convertChartoHex для чего если файл в бинарном формате? На вскидку я бы ожидал такое решение — в цикле читаем входной файл блоками, например по 4к байт (и храним в памяти только 1 текущий блок, а не все), с конца в начало. Затем инвертируем вычитанный блок и пишем/добавляем его в выходной файл, все.

Или аккуратно замапить входной файл в память, дальше тривиально

Но зачем

Сделать обработку небуферезирующую весь файл? Это ж паттерн для i/о api в любом языке, как низко так и высокоуровневого, особенно там где есть memory pooling, backpressure и т.д.

реализация драйвера тут не при чем — речь идёт о том что бы не грузить огромный файл целиком в память. Работает этот подход везде одинаково в Java, js, .net делают точно так же.

для чого вантажити в пам"ять, якщо можна читати побайтно?

Так об этом и речь выше и вопрос зачем так делать :)

С++ має компілятор, а про І/О я вже писав нижче: читання на рівні системи і так іде блоками, а далі, ще кешується (буферизується) кілька разів....не думаю, що можна передбачити як буде вести себе read write seek в рілтаймі

стоимость call в ядро ненулевая. быстрее блоками самому читать

А чтение это не сискол? :) На самом деле файл-мэппинг будет одним из быстрых способов, т.к. ОС будет трапаться только тогда, когда закончится наличие реального бекенда файла в памяти, ОС подгрузит ещё большой кусок, выгрузив старый, если нужно. И если не считать трапа, то 0 сисколов вообще.

А чтение это не сискол?

побайтно из буфера? нет

кстати, я сомневаюсь, что файлмэппинг будет работать для файлов больше 4ГБ на 32битных системах

побайтно из буфера? нет

Если про С++, то буфера ведь заканчиваются и оно вызовет сискол.

кстати, я сомневаюсь, что файлмэппинг будет работать для файлов больше 4ГБ на 32битных системах

Будет. Надо использовать 64 битные оффсеты:

#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64

И вперёд мапить по гигу за раз, потом мапить следующий кусок и т.д.

И вперёд мапить по гигу за раз, потом мапить следующий кусок и т.д.

тсююю. так не интересно

там выше с побайтным fseek все имхо будет оптимально в конце концов, с правильной буферизацией на уровне libc.

я так розумію, є заява, робити закат сонця вручну (брати на себе фунціональність ОС)

я так поняв, рєбята пропонують «оптімізіровать» I\О операції (хотя читання з диска, тобто блочного пристоя йде блоками, так само і пам"ять, відображається сторінками, можливо кешується кілька разів)....

маппинг файлов на сегодня всё ещё самый быстрый доступ к файлам ну вообще теоритически самый быстрый какой можно Майк написал почему так причём настолько быстрый что сделали даже специальную функцию SendFile которая читает файл и пишет сразу же ж в сокет соотв. напрямую.

при том что маппинг юзает твой файл напрямую вообще без каких-либо буферов а сокеты там при том что и сокеты тогда юзают файл напрямую через единый буфер в который сразу читается файл и сразу из него пишется в сокет ничего вообще никуда больше не копируя и даже не передавая на user level.

так уж получилось ((

en.wikipedia.org/wiki/Paging

в принципі да, так як I\O до HDD довше чим до RAM,
думаю що малося на увазі, при підчкачці файла з на диск, можна застосовувати зеро-копі для інмеморі даних

то вот это держать в RAM

redis\memcached

Да-да, а в случае вызова нескольких функций на каждый байт, эти накладные расходы будут составлять львиную долю ресурсозатрат.

причём оба два.

Мне кажется у винчестера есть собственный буфер и читает он за раз не один байт. Так что Seek() не гоняет голову (в классических винчестерах). В ссд по-идее тоже что-то похожее.

(...биоцца галавой ап стину...)

портфолио

Что за портфолио?

там, где за количество строк платят

Підписатись на коментарі