Объясните этот код C #: byte * p = (byte *) (void *) Scan0; - PullRequest
1 голос
/ 30 октября 2009

Я нашел код из сети, в котором я не могу понять эту строку: -

byte* p = (byte*)(void*)Scan0;

Там Scan0 равен System.IntPtr. Это код C # .Net. Пожалуйста, объясните приведенную выше строку.

Полный код приведен ниже. это код для преобразования изображения в оттенки серого.

public static Image GrayScale(Bitmap b)
    {

        BitmapData bmData = b.LockBits(new Rectangle(0, 0, b.Width, b.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);

        int stride = bmData.Stride;
        System.IntPtr Scan0 = bmData.Scan0;

        unsafe
        {
            byte* p = (byte*)(void*)Scan0;

            int nOffset = stride - b.Width * 3;

            byte red, green, blue;

            for (int y = 0; y < b.Height; ++y)
            {
                for (int x = 0; x < b.Width; ++x)
                {
                    blue = p[0];
                    green = p[1];
                    red = p[2];

                    p[0] = p[1] = p[2] = (byte)(.299 * red + .587 * green + .114 * blue);

                    p += 3;
                }
                p += nOffset;
            }
        }

        b.UnlockBits(bmData);

        return (Image)b;
    }

Я понимаю весь код, но проблема только в этой строке.

byte* p = (byte*)(void*)Scan0;

Ответы [ 6 ]

5 голосов
/ 30 октября 2009

Сначала преобразует IntPtr в указатель void. Затем к указателю byte. Это unsafe код.

Подробнее о небезопасном коде: http://msdn.microsoft.com/en-us/library/aa288474%28VS.71%29.aspx

Как отмечает Роберт Харви, указатель - это область памяти. В C / C ++ массивы тесно связаны с этой концепцией. Когда это делает квадратные скобки, это в основном регулирует адрес.

4 голосов
/ 30 октября 2009

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

Вы, вероятно, запутались здесь, потому что нет никаких оснований для того, чтобы сначала привести Scan0 к пустоте *. Приведение к байту * будет работать так же хорошо.

2 голосов
/ 03 апреля 2010

IntPtr имеет явный оператор (void *), который позволяет приведение к void *. Если вы попытаетесь привести непосредственно из IntPtr к чему-то другому, компилятор прекратит работу, потому что для класса IntPtr определено только приведение типа void *. Смотрите также IntPtr :: ToPointer ().

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

1 голос
/ 30 октября 2009

Ознакомьтесь с этим руководством по небезопасному коду. Он объяснит, что означает строка кода и как ее можно использовать для других типов, кроме байта:

http://msdn.microsoft.com/en-us/library/aa288474(VS.71).aspx

По сути, небезопасный код позволяет использовать указатели в стиле c.

1 голос
/ 30 октября 2009

Это выглядит странно, но тогда я не очень хорошо знаю C #. может быть в том, что есть какая-то проблема с приведением System.IntPtr непосредственно к byte*, но не с System.IntPtr на void* или void* на byte*.

Конечный результат, вероятно, такой же, как если бы вы разыграли int* в char* в C: возможность разыменовать p для получения одного байта целого числа (предполагая, что CHAR_BIT равен 8 в реализации C).

0 голосов
/ 06 ноября 2009

Возможно ли, что вам нужно привести к void, чтобы объект не выполнил какой-либо код для самостоятельного преобразования?

...