Проблема, которую вы описываете, представляет собой цепочку (к сожалению, 1 ) ошибок и недоразумений.Позвольте мне попытаться подробно описать, что происходит, надеюсь, вам понадобится время, чтобы прочитать весь материал: он длинный, но это очень важные основы, которые должен освоить любой программист.Пожалуйста, не отчаивайтесь, если вы не до конца понимаете все это: просто попробуйте поиграть с этим, вернитесь через неделю или две, попрактикуйтесь, посмотрите, что произойдет:)
Существует существенная разница междупонятия символа кодировка и символа набор .Пока вы действительно не поймете эту разницу, вы никогда не поймете, что происходит здесь.Джоэл Спольски (один из основателей Stackoverflow, если подумать об этом) недавно написал статью, объясняющую разницу: Абсолютный минимум каждый разработчик программного обеспечения Абсолютно, положительно должен знать о Unicode и наборах символов (без оправданий!).Прежде чем продолжить читать, прежде чем продолжить программирование, даже прочитайте это.Честно, почитай, пойми: название не преувеличено.Вы должны точно знать это.
После этого давайте продолжим:
Когда программа на C запускается, в ячейке памяти, которая должна содержать значение типа "char", содержится толькокак и любая другая ячейка памяти, последовательность единиц и нулей.«Тип» переменной означает что-то только для компилятора, а не для работающей программы, которая просто видит единицы и обнуляет и не знает больше этого.Другими словами: если вы обычно думаете о «букве» (элементе из символа set ), находящемся где-то в памяти, то, что на самом деле есть битовая последовательность (элемент из кодировки символа )).
Каждый компилятор может использовать любую кодировку, которую он желает представлять символами в памяти.Как следствие, он может представлять то, что мы называем «новой строкой» внутри себя, как любое выбранное число.Например, скажем, я пишу компилятор, я могу согласиться с тем, что каждый раз, когда я хочу сохранить внутреннюю «новую строку», я сохраняю ее как число шесть (6), что составляет просто 0x6 в двоичном (или 110 в двоичном).
Запись в файл выполняется сообщением операционной системы 2 о четырех вещах одновременно:
- Тот факт, что вы хотите записать в файл (
fwrite()
) - Где начинаются данные, которые вы хотите записать (первый аргумент
fwrite
) - Сколько данных вы хотите записать (второй и третий аргумент, умноженные)
- В какой файл вы хотите записать (последний аргумент)
Обратите внимание, что это не имеет никакого отношения к «типу» этих данных: ваша работа не имеет представления и не заботится,Он ничего не знает о наборах символов и ему все равно: он просто видит последовательность единиц и нулей, начинающихся где-то, и копирует их в файл.
Открытие файла в «двоичном» режиме на самом деле является нормальнымИнтуитивно понятный способ работы с файлами, который может ожидать начинающий программист: указанная вами область памяти копируется один в один в файл.Если вы записываете в память место, которое использовалось для хранения переменных, которые компилятор решил сохранить как тип «char», эти значения записываются в файл один на один.Если вы не знаете, как компилятор хранит значения внутри себя (какое значение он связывает с символом новой строки, с буквой «a», «b» и т. Д.), ЭТО ЗНАЧИТЕЛЬНО.Сравните это с аналогичным замечанием Джоэла о том, что текстовый файл бесполезен, не зная, какова его кодировка: то же самое.
Открытие файла в «текстовом» режиме почти равно бинарному режиму, с одним (и только одним) отличием: каждый раз, когда записывается значение, значение которого равно тому, что компилятор использует ВНУТРЕННИЙ для новой строки (6, в нашемcase), он записывает в файл что-то другое: не то значение, а то, какую операционную систему вы используете, считает новой строкой.В Windows это два байта (13 и 10 или 0x0d 0x0a в Windows).Заметьте, опять же, если вы не знаете о выборе компилятором внутреннего представления других символов, это ПОСТОЯННО БЕЗУМНО.
Обратите внимание, что на данный момент довольно ясно, что запись чего-либо, кроме данных, которые назначил компиляторпоскольку символы для файла в текстовом режиме - плохая идея: в нашем случае цифра 6 может оказаться просто среди значений, которые вы пишете, и в этом случае выходные данные изменяются так, как мы абсолютно не хотим.
(Un) К счастью, большинство (все?) Компиляторов фактически используют одно и то же внутреннее представление для символов: это представление US-ASCII и является матерью всех значений по умолчанию.По этой причине вы можете записать некоторые «символы» в файл в вашей программе, скомпилированный любым произвольным компилятором, а затем открыть его с помощью текстового редактора: все они используют / понимают US-ASCII, и это работает.
Хорошо, теперь, чтобы связать это с вашим примером: почему нет разницы между написанием «теста» в двоичном режиме и в текстовом режиме? Поскольку в "test" нет новой строки, вот почему!
И что это значит, когда вы "открываете файл", а затем "видите" символы?Это означает, что программа, которую вы использовали для проверки последовательности единиц и нулей в этом файле (потому что на вашем жестком диске все равно единице и нулю) решила интерпретировать это как US-ASCII, и именно это ваш код компилятор решил закодироватьэта строка как, в ее памяти.
Бонусные пункты: напишите программу, которая считывает единицы и нули из файла в память и печатает каждый бит (есть несколько битов, чтобы составить один байт, для их извлечения вам нужночтобы узнать хитрые операторские трюки, Google!) как «1» или «0» для пользователя.Обратите внимание, что «1» - это ХАРАКТЕР 1, точка в выбранном вами наборе символов, поэтому ваша программа должна взять бит (число 1 или 0) и преобразовать его в последовательность битов, необходимых для представления символа 1 или 0 вкодирование, которое использует эмулятор терминала, что вы просматриваете стандарт из программы на Боже мой.Хорошая новость: вы можете использовать множество коротких путей, допуская US-ASCII везде.Эта программа покажет вам, что вы хотели: последовательность единиц и нулей, которую ваш компилятор использует для внутреннего представления «теста».
Этот материал действительно пугающий для новичков, и я знаю, что это заняло у меня много временидаже знать, что было разницей между набором символов и кодировкой, не говоря уже о том, как все это работало.Надеюсь, я не демотивировал тебя, если бы я это сделал, просто помни, что ты никогда не сможешь потерять знания, которые у тебя уже есть, только получить их (хорошо, не всегда так: P).В жизни нормально, что в заявлении возникает больше вопросов, чем в ответе. Сократ знал это, и его мудрость беспрепятственно применима к современным технологиям спустя 2,4 тыс. Лет.
Удачи, не стесняйтесь продолжать задавать вопросы.Другим читателям: пожалуйста, улучшайте этот пост, если вы видите ошибки.
Hraban
1 Человек, который сказал вам, что "сохранение файла в двоичном формате, вероятно,меньше », например, вероятно серьезно неправильно понимает эти основы.Если только он не имел в виду сжатие данных перед тем, как сохранить их, в этом случае он просто использует запутанное слово («двоичный») для «сжатый».
2 , сообщающий операционной системе"что-то" - это то, что обычно называют системным вызовом.