C++ (Cpp) Fixed — 30 примеров найдено. Это лучшие примеры C++ (Cpp) кода для Fixed, полученные из open source проектов. Вы можете ставить оценку каждому примеру, чтобы помочь нам улучшить качество примеров.
Основные методы
Основные методы
Основные методы
GTEST_TEST(Fixed, version)
Top 8 Linux Commands Every Linux Us.
Источник: cpp.hotexamples.com
Какая польза от ключевого слова С# исправлено/небезопасно? [дубликат]
Вам нужно исправить это, чтобы указатель, который вы используете, оставался действительным. Но, честно говоря, случаи использования небезопасного кода относительно редки. Я много лет пишу на C# и до сих пор даже не помню различных правил небезопасного кодирования. — Jon Skeet
Проверь это: msdn.microsoft.com/en-us/library/f58wzh21.aspx — w.b
Отсутствие ответа объясняет это утверждение, найденное в связанном примере: «Существует небольшая стоимость использования фиксированного оператора. Так это только поможет на операции, которые тратят значительное количество времени в небезопасном коде», что, по крайней мере, неоднозначно, возможно, неправильно, в зависимости от того, как вы читаете первую часть. Неясно, корректируются ли CLR «нефиксированные» указатели, когда GC перемещает выделенный блок памяти (за счет некоторой потери времени) , или нет, и начинают указывать не на то место (поэтому ключевое слово ‘fixed’ не необязательный но обязательно с указателями — это мое понимание). — mins
Mixed Messages (Official video)
3 ответы
C # — это управляемый язык это означает, что память управляется автоматически, т.е. не вами. Если вы не использовали fixed к тому времени, когда вы приступите к изменению памяти, на которую указывает ваш указатель, C# мог бы переместить переменную в другую ячейку памяти, поэтому вы могли бы изменить что-то еще! fixed логически фиксирует переменную в памяти, чтобы она не перемещалась.
Почему С# перемещает переменные в памяти? Чтобы сжать память, в противном случае программы будут использовать больше доступной им памяти, если объекты, которые больше не существуют, оставляют дыры, в которые не могут поместиться другие объекты (фрагментация кучи памяти). я использовал fixed широко в .NET-библиотеке разработан для устройств с ограниченными ресурсами, чтобы избежать копирования мусора в буферы, и найти эту функцию, которой очень не хватает в других управляемых языках, где вы не можете сделать то же самое. При написании игр на управляемом языке сборка мусора часто является одним из самых больших узких мест, поэтому возможность не создавать ее очень полезна! Смотрите мой вопрос здесь: С# Копировать переменные в буфер, не создавая мусора? по одной причине.
ответ дан 26 мар ’23, в 00:03
«Я широко использовал fix в библиотеке .NET, предназначенной для устройств с ограниченными ресурсами, чтобы избежать копирования мусора в буферы, и обнаружил, что этой функции очень не хватает в других управляемых языках, где вы не можете сделать то же самое. При написании игр на управляемом языке сборка мусора часто одно из самых больших узких мест, поэтому возможность не создавать его очень полезна!» —> Спасибо, но извините, не могли бы вы уточнить. Кажется, я понял, что на самом деле закрепление памяти предназначено для производительности. Но я на самом деле. не понимаю, как, был бы признателен, если бы вы уточнили это! — Мазок. Джат
C/C++ и C# что это такое?
Закрепление памяти не дает производительности возможности использовать указатели для изменения памяти, в моем случае копирование нескольких переменных в буфер без создания мусорного бака дает производительность, когда время сборки мусора является проблемой, см. мой связанный вопрос. — маркмнл
Спасибо, Марк. Прочтите это. Интересно, какой прирост производительности вы получили, не используя промежуточный байт [] и вместо этого копируя через закрепленную область памяти? Было ли это значительным? — Мазок. Джат
Если вы находитесь на телефоне или устройстве, таком как Ouya (запускает моно) и много копируете, это было заметно — приложение зависает, когда должен работать GC — теперь этого не происходит, потому что мусора нет. — маркмнл
Большое спасибо за ваш вклад. — Мазок. Джат
- он позволяет закрепить массив и получить указатель на данные
- при использовании в unsafe struct поле, оно объявляет «фиксированный буфер» — зарезервированный блок пространства в типе, доступ к которому осуществляется с помощью указателей, а не обычных полей.
Чтобы ответить на конкретном примере — вот некоторый код, который используется для выполнения семантического равенства между двумя byte[] произвольного размера.
internal static unsafe int GetHashCode(byte[] value) < unchecked < if (value == null) return -1; int len = value.Length; if (len == 0) return 0; int octects = len / 8, spare = len % 8; int acc = 728271210; fixed (byte* ptr8 = value) < long* ptr64 = (long*)ptr8; for (int i = 0; i < octects; i++) < long val = ptr64[i]; int valHash = (((int)val) ^ ((int)(val >> 32))); acc = (((acc int offset = len — spare; while(spare— != 0) < acc = (((acc > return acc; > >
Итак, если, например, в буфере было 1000 элементов, рассматривая его как набор long теперь мы делаем только 125 итераций, а не просматриваем все 1000 по отдельности, плюс мы полностью обходим любую проверку границ массива (которую JIT может или не может удалить, в зависимости от того, как Очевидный похоже, что вы не можете их нарушать).
Спасибо, Марк — «например, в буфере было 1000 элементов, рассматривая его как набор длинных, мы теперь делаем только 125 итераций, а не просматриваем все 1000 по отдельности» — не уверен, что я следую за вами, но я предполагаю вы говорите, что это в основном «Соблюдение производительности». Если у вас есть большой граф объектов — иногда будет быстрее, если вы зафиксируете/фиксируете его расположение в памяти во время итерации по нему? Если это так, то это единственное «практическое» использование, которое я слышал до сих пор (все остальные просто повторяют «да, исправьте это в памяти») — Мазок. Джат
привет Марк, спасибо. Марк привел мне очень полезный пример — stackoverflow.com/questions/15307431/… — Мазок. Джат
Unsafe кодовые блоки используются довольно редко. Они преимущественно используются, если вы хотите создавать и использовать указатели. Кроме того, CLR не может контролировать любой код в небезопасном блоке. Это считается неподдающимся проверке (из MSDN) в отношении CLR.
Теперь, когда происходит сборка мусора, какой-то объект вполне может быть перемещен. При префиксе fixed мы говорим платформе не перемещать объекты, на которые указывают указатели адресов.
Обратите внимание, что «Исправлено» — это проблема взаимодействия. КОГДА вы получаете указатель и передаете его неуправляемому коду (например, собственной dll для сброса туда некоторых данных), вы НЕ МОЖЕТЕ, чтобы сборщик мусора перемещал этот объект во время выполнения вашего вызова. Следовательно, фиксируя его на месте. — TomTom
Вот что говорит MSDN — исправьте расположение памяти, да, я понял. Но почему? Любое практическое использование, зачем нам вообще нужна эта языковая функция? Спасибо — Мазок. Джат
В основном при выполнении взаимодействия и маршалинга. Если вы хотите сохранить указатели на более длительное время. — датский язык
Не тот ответ, который вы ищете? Просмотрите другие вопросы с метками c# or задайте свой вопрос.
Источник: stackovergo.com
Указатели C++
Указатели, без сомнения, — один из самых важных и сложных аспектов C++. В значительной степени мощь многих средств C++ определяется использованием указателей. Например, благодаря им обеспечивается поддержка связных списков и динамического выделения памяти, и именно они позволяют функциям изменять содержимое своих аргументов. Однако об этом мы поговорим в последующих главах, а пока (т.е. в этой главе) мы рассмотрим основы применения указателей и покажем, как можно избежать некоторых потенциальных проблем, связанных с их использованием.
При рассмотрении темы указателей нам придется использовать такие понятия, как размер базовых С++-типов данных. В этой главе мы предположим, что символы занимают в памяти один байт, целочисленные значения — четыре, значения с плавающей точкой типа float — четыре, а значения с плавающей точкой типа double — восемь (эти размеры характерны для типичной 32-разрядной среды).
Что представляют собой указатели
Указатели — это переменные, которые хранят адреса памяти. Чаще всего эти адреса обозначают местоположение в памяти других переменных. Например, если х содержит адрес переменной у, то о переменной, х говорят, что она «указывает» на у.
Указатель — это переменная, которая содержит адрес другой переменной.
Переменные-указатели (или переменные типа указатель) должны быть соответственно объявлены. Формат объявления переменной-указателя таков:
тип *имя_переменной;
Здесь элемент тип означает базовый тип указателя, причем он должен быть допустимым С++-типом. Элемент имя_переменной представляет собой имя переменной-указателя. Рассмотрим пример. Чтобы объявить переменную р указателем на int-значение, используйте следующую инструкцию.
int *р;
Для объявления указателя на float-значение используйте такую инструкцию.
float *р;
В общем случае использование символа «звездочка» (*) перед именем переменной в инструкции объявления превращает эту переменную в указатель.
Базовый тип указателя определяет тип данных, на которые он будет ссылаться.
Тип данных, на которые будет ссылаться указатель, определяется его базовым типом. Рассмотрим еще один пример.
int *ip; // указатель на целочисленное значение
double *dp; // указатель на значение типа double
Как отмечено в комментариях, переменная ip — это указатель на int-значение, поскольку его базовым типом является тип int, а переменная dp — указатель на double-значение, поскольку его базовым типом является тип double, Следовательно, в предыдущих примерах переменную ip можно использовать для указания на int-значения, а переменную dp на double-значения. Однако помните: не существует реального средства, которое могло бы помешать указателю ссылаться на «бог-знает-что». Вот потому-то указатели потенциально опасны.
Операторы, используемые с указателями
С указателями используются два оператора: «*» и «» — унарный. Он возвращает адрес памяти, по которому расположен его операнд. (Вспомните: унарному оператору требуется только один операнд.) Например, при выполнении следующего фрагмента кода
balptr = &balance;
в переменную balptr помещается адрес переменной balance. Этот адрес соответствует области во внутренней памяти компьютера, которая принадлежит переменной balance. Выполнение этой инструкции никак не повлияло на значение переменной balance. Назначение оператора можно «перевести» на русский язык как «адрес переменной», перед которой он стоит.
Следовательно, приведенную выше инструкцию присваивания можно выразить так: «переменная balptr получает адрес переменной balance». Чтобы лучше понять суть этого присваивания, предположим, что переменная balance расположена в области памяти с адресом 100. Следовательно, после выполнения этой инструкции переменная balptr получит значение 100.
Второй оператор работы с указателями (*) служит дополнением к первому (
переменной value будет присвоено значение переменной balance, на которую указывает переменная balptr. Например, если переменная balance содержит значение 3200, после выполнения последней инструкции переменная value будет содержать значение 3200, поскольку это как раз то значение, которое хранится по адресу 100. Назначение оператора «*» можно выразить словосочетаинем «по адресу».
В данном случае предыдущую инструкцию можно прочитать так: «переменная value получает значение (расположенное) по адресу balptr». Действие приведенных выше двух инструкций схематично показано на рис. 6.1.
Последовательность операций, отображенных на рис. 6.1, реализуется в следующей программе.
using namespace std;
>
При выполнении этой программы получаем такие результаты:
Баланс равен: 3200
К сожалению, знак умножения (*) и оператор со значением «по адресу» обозначаются одинаковыми символами «звездочка», что иногда сбивает с толку новичков в языке C++. Эти операции никак не связаны одна с другой. Имейте в виду, что операторы «*» и «f; // ОШИБКА!
Некорректность этого фрагмента состоит в недопустимости присваивания double-указателя int-указателю. Выражение f; // Теперь формально все ОК!
Операция приведения к типу (int *) вызовет преобразование double- к int-указателю. Все же использование операции приведения в таких целях несколько сомнительно, поскольку именно базовый тип указателя определяет, как компилятор будет обращаться с данными, на которые он ссылается. В данном случае, несмотря на то, что p (после выполнения последней инструкции) в действительности указывает на значение с плавающей точкой, компилятор по-прежнему «считает», что он указывает на целочисленное значение (поскольку р по определению — int-указатель).
Чтобы лучше понять, почему использование операции приведения типов при присваивании одного указателя другому не всегда приемлемо, рассмотрим следующую программу.
// Эта программа не будет выполняться правильно.
using namespace std;
p = (int *) // Используем операцию приведения типов для присваивания double-указателя int-указателю.
у = *р; // Что происходит при выполнении этой инструкции?
>
Как видите, в этой программе переменной p (точнее, указателю на целочисленное значение) присваивается адрес переменной х (которая имеет тип double). Следовательно, когда переменной y присваивается значение, адресуемое указателем р, переменная y получает только четыре байт данных (а не все восемь, требуемые для double-значения), поскольку р— указатель на целочисленный тип int. Таким образом, при выполнении cout-инструкции на экран будет выведено не число 123.23, а, как говорят программисты, «мусор». (Выполните программу и убедитесь в этом сами.)
Присваивание значений с помощью указателей
При присваивании значения области памяти, адресуемой указателем, его (указатель) можно использовать с левой стороны от оператора присваивания. Например, при выполнении следующей инструкции (если р — указатель на целочисленный тип)
*р = 101;
число 101 присваивается области памяти, адресуемой указателем р. Таким образом, эту инструкцию можно прочитать так: «по адресу р помещаем значение 101». Чтобы инкрементировать или декрементировать значение, расположенное в области памяти, адресуемой указателем, можно использовать инструкцию, подобную следующей.
(*р)++;
Круглые скобки здесь обязательны, поскольку оператор «*» имеет более низкий приоритет, чем оператор «++».
Присваивание значений с использованием указателей демонстрируется в следующей программе.
using namespace std;
>
Вот такие результаты генерирует эта программа.
100 101 100
Использование указателей в выражениях
Указатели можно использовать в большинстве допустимых в C++ выражений. Но при этом следует применять некоторые специальные правила и не забывать, что некоторые части таких выражений необходимо заключать в круглые скобки, чтобы гарантированно получить желаемый результат.
Арифметические операции над указателями
С указателями можно использовать только четыре арифметических оператора: ++, — , + и — . Чтобы лучше понять, что происходит при выполнении арифметических действий с указателями, начнем с примера. Пусть p1 — указатель на int-переменную с текущим значением 2 ООО (т.е. p1 содержит адрес 2 ООО). После выполнения (в 32-разрядной среде) выражения
p1++;
содержимое переменной-указателя p1 станет равным 2 004, а не 2 001! Дело в том, что при каждом инкрементировании указатель p1 будет указывать на следующее int-значение. Для операции декрементирования справедливо обратное утверждение, т.е. при каждом декрементировании значение p1 будет уменьшаться на 4. Например, после выполнения инструкции
p1—;
указатель p1 будет иметь значение 1 996, если до этого оно было равно 2 000. Итак, каждый раз, когда указатель инкрементируется, он будет указывать на область памяти, содержащую следующий элемент базового типа этого указателя. А при каждом декрементировании он будет указывать на область памяти, содержащую предыдущий элемент базового типа этого указателя.
Для указателей на символьные значения результат операций инкрементирования и декрементирования будет таким же, как при «нормальной» арифметике, поскольку символы занимают только один байт. Но при использовании любого другого типа указателя при инкрементировании или декрементировании значение переменной-указателя будет увеличиваться или уменьшаться на величину, равную размеру его базового типа.
Арифметические операции над указателями не ограничиваются использованием операторов инкремента и декремента. Со значениями указателей можно выполнять операции сложения и вычитания, используя в качестве второго операнда целочисленные значения. Выражение
p1 = p1 + 9;
заставляет p1 ссылаться на девятый элемент базового типа указателя p1 относительно элемента, на который p1 ссылался до выполнения этой инструкций.
Несмотря на то что складывать указатели нельзя, один указатель можно вычесть из другого (если они оба имеют один и тот же базовый тип). Разность покажет количество элементов базового типа, которые разделяют эти два указателя.
Помимо сложения указателя с целочисленным значением и вычитания его из указателя, а также вычисления разности двух указателей, над указателями никакие другие арифметические операции не выполняются. Например, с указателями нельзя складывать float- или double-значения.
Чтобы понять, как формируется результат выполнения арифметических операций над указателями, выполним следующую короткую программу. Она выводит реальные физические адреса, которые содержат указатель на int-значение (i) и указатель на float-значение (f). Обратите внимание на каждое изменение адреса (зависящее от базового типа указателя), которое происходит при повторении цикла. (Для большинства 32-разрядных компиляторов значение i будет увеличиваться на 4, а значение f — на 8.) Отметьте также, что при использовании указателя в cout-инструкции его адрес автоматически отображается в формате адресации, применяемом для текущего процессора и среды выполнения.
// Демонстрация арифметических операций над указателями.
using namespace std;
>
Вот как выглядит возможный вариант выполнения этой программы (ваши результаты могут отличаться от приведенных, но интервалы между значениями должны быть такими же).
0012FE80 0012FECC
Узелок на память. Все арифметические операции над указателями выполняются относительно базового типа указателя.
Сравнение указателей
Указатели можно сравнивать, используя операторы отношения ==, < и >. Однако для того, чтобы результат сравнения указателей поддавался интерпретации, сравниваемые указатели должны быть каким-то образом связаны. Например, если p1 и р2 — указатели, которые ссылаются на две отдельные и никак не связанные переменные, то любое сравнение p1 и р2 в общем случае не имеет смысла. Но если p1 и р2 указывают на переменные, между которыми существует некоторая связь (как, например, между элементами одного и того же массива), то результат сравнения указателей p1 и р2 может иметь определенный смысл. Ниже в этой главе мы рассмотрим пример программы, в которой используется сравнение указателей.
Указатели и массивы
В C++ указатели и массивы тесно связаны между собой, причем настолько, что зачастую понятия «указатель» и «массив» взаимозаменяемы. В этом разделе мы попробуем проследить эту связь. Для начала рассмотрим следующий фрагмент программы.
p1 = str;
Здесь str представляет собой имя массива, содержащего 80 символов, a p1 — указатель на тип char. Особый интерес представляет третья строка, при выполнении которой переменной p1 присваивается адрес первого элемента массива str. (Другими словами, после этого присваивания p1 будет указывать на элемент str[0].) Дело в том, что в C++ использование имени массива без индекса генерирует указатель на первый элемент этого массива. Таким образом, при выполнении присваивания p1 = str адрес stг[0] присваивается указателю p1. Это и есть ключевой момент, который необходимо четко понимать: неиндексированное имя массива, использованное в выражении, означает указатель на начало этого массива.
Имя массива без индекса образует указатель на начало этого массива.
Поскольку после рассмотренного выше присваивания p1 будет указывать на начало массива str, указатель p1 можно использовать для доступа к элементам этого массива. Например, если нужно получить доступ к пятому элементу массива str, используйте одно из следующих выражений:
*(p1+4)
В обоих случаях будет выполнено обращение к пятому элементу. Помните, что индексирование массива начинается с нуля, поэтому при индексе, равном четырем, обеспечивается доступ к пятому элементу. Точно такой же эффект производит суммирование значения исходного указателя (p1) с числом 4, поскольку p1 указывает на первый элемент массива str.
Необходимость использования круглых скобок, в которые заключено выражение p1+4, обусловлена тем, что оператор «*» имеет более высокий приоритет, чем оператор «+». Без этих круглых скобок выражение бы свелось к получению значения, адресуемого указателем p1, т.е. значения первого элемента массива, которое затем было бы увеличено на 4.
Важно! Убедитесь лишний раз в правильности использования круглых скобок в выражении с указателями. В противном случае ошибку будет трудно отыскать, поскольку внешне программа может выглядеть вполне корректной. Если у вас есть сомнения в необходимости их использования, примите решение в их пользу — вреда от этого не будет.
В действительности в C++ предусмотрено два способа доступа к элементам массивов: с помощью индексирования массивов и арифметики указателей. Дело в том, что арифметические операции над указателями иногда выполняются быстрее, чем индексирование массивов, особенно при доступе к элементам, расположение которых отличается строгой упорядоченностью. Поскольку быстродействие часто является определяющим фактором при выборе тех или иных решений в программировании, то использование указателей для доступа к элементам массива— характерная особенность многих С++-программ. Кроме того, иногда указатели позволяют написать более компактный код по сравнению с использованием индексирования массивов.
Чтобы лучше понять различие между использованием индексирования массивов и арифметических операций над указателями, рассмотрим две версии одной и той же программы. В этой программе из строки текста выделяются слова, разделенные пробелами. Например, из строки «Привет дружище» программа должна выделить слова «Привет» и «дружище».
Программисты обычно называют такие разграниченные символьные последовательности лексемами (token). При выполнении программы входная строка посимвольно копируется в другой массив (с именем token) до тех пор, пока не встретится пробел. После этого выделенная лексема выводится на экран, и процесс продолжается до тех пор, пока не будет достигнут конец строки. Например, если в качестве входной строки использовать строку Это лишь простой тест., программа отобразит следующее.
тест.
Вот как выглядит версия программы разбиения строки на слова с использованием арифметики указателей.
// Программа разбиения строки на слова:
// версия с использованием указателей.
using namespace std;
// Считываем лексему из строки.
q = token; // Устанавливаем q для указания на начало массива token.
/* Считываем символы до тех пор, пока не встретится либо пробел, либо нулевой символ (признак завершения строки). */
if (*p) р++; // Перемещаемся за пробел.
*q = ‘