В чем разница между ptr[i] и *(ptr i)?

#c# #.net #arrays #pointers

#c# #.net #массивы #указатели

Вопрос:

При использовании указателя на массив я всегда обращался к элементам с помощью индексатора, такого как, myPtr[i] = stuff ; однако недавно я BitConverter просматривал реализацию и обнаружил, что доступ к элементам осуществлялся с помощью, *(myPtr i) = stuff .

Что мне показалось довольно странным, поскольку оба метода (насколько я знаю) делают одно и то же, то есть возвращают адрес myPtr i , за исключением (на мой взгляд) метода индексатора, который выглядит намного более читаемым.

Итак, почему Microsoft решила увеличивать указатели так, как они это делали, в чем разница между этими двумя методами (есть ли преимущества в производительности)?

Комментарии:

1. Они генерируют один и тот же IL. Это просто вопрос стиля.

2. ToBoolean Метод отличный. Комментарии не соответствуют коду, и он имеет отличный x == 0 ? false : true шаблон вместо простого x != 0 .

Ответ №1:

Как вы заявили, они делают то же самое.

Фактически, при доступе к an int* оба ptr[i] *(ptr i) синтаксиса и будут пропускать проверку границ и указывать на некоторую память за пределами границ массива, если i она больше длины массива.

Я почти уверен, что C #, как и C , унаследовал индексированный доступ к указателю массива, используя *(ptr index) синтаксис из C. Я почти уверен, что это единственная причина, по которой доступны оба синтаксиса.

Комментарии:

1. Так myPrt[i] это просто синтаксический сахар? Никаких других различий, кроме этого?

2. @Sam Да, другой разницы быть не должно.

3. @dcastro Насколько я помню, использование индексатора может дать вам IndexOutOfRangeException , в то время *(ptr index) как просто укажет вам на некоторую память за пределами массива.

4. @AndreySarafanov Использование индексатора даст вам IOR, например, если вы обращаетесь к массиву int. Если вы обращаетесь к an int* , то оба [index] *(ptr index) синтаксиса и будут указывать на некоторую память вне массива. Оба синтаксиса будут пропускать границы -проверьте.

5. @dcastro Спасибо, мой плохой, должен был более внимательно прочитать вопрос.

Ответ №2:

Из спецификации языка CSharp (18.5.3):

Доступ к элементу указателя вида P[E] вычисляется точно как *(P E). (…) Оператор доступа к элементу указателя не проверяет наличие ошибок, выходящих за пределы, и поведение при доступе к элементу, выходящему за пределы, не определено. Это то же самое, что C и C .

Различий нет.

Ответ №3:

Чтобы прояснить разницу между [] оператором массива и указателем (что обсуждалось в ответе dcastro), вы можете проверить вывод приведенного ниже кода.

 unsafe {
    int[] arr = new[] { 1, 2 };
    fixed(int* ptr = arr) {
        for(int i = 0; i < arr.Length   1; i  ) {
            try { System.Console.WriteLine(*(ptr   i)); } catch(Exception e) { System.Console.WriteLine(e.Message); }
            try { System.Console.WriteLine(ptr[i]); } catch (Exception e) { System.Console.WriteLine(e.Message); }
            try { System.Console.WriteLine(arr[i]); } catch (Exception e) { System.Console.WriteLine(e.Message); }
        }
    }
}
  

Вывод

 1
1
1
2
2
2
0
0
Index was outside the bounds of the array.