#c# #c #pointers
#c# #c #указатели
Вопрос:
Я знаю, что это странный вопрос, и я рискую показать свою неопытность, но я тут рву на себе волосы.
У меня есть пример C , который работает так, как ожидалось. Вот фрагмент надоедливого бита:
BIRDFRAME frame;
birdGetMostRecentFrame(GROUP_ID,amp;frame);
BIRDREADING *bird_data;
bird_time=frame.dwTime;
for(FBBloop=FBBstart; FBBloop<FBBend; FBBloop )
{
bird_data = amp;frame.reading[FBBloop];
// Do stuff
}
Обратите внимание, что bird_data
это указатель, которому присваивается адрес frame.reading[FBBloop]
. Мое приложение написано на C # и поэтому не имеет ничего из этих ошибок с указателями. Соответствующий бит выглядит следующим образом:
FlockOfBirds.BIRDFRAME frame = new FlockOfBirds.BIRDFRAME();
FlockOfBirds.birdGetMostRecentFrame(1, ref frame);
Console.WriteLine("T:{0}",frame.dwTime.ToString());
FlockOfBirds.BIRDREADING reading;
for (int k = 1; k <= sysconf.byNumDevices; k )
{
reading = frame.readings[k];
Console.WriteLine(" [{0}][{1}][{2}]", reading.position.nX.ToString(), reading.position.nY.ToString(), reading.position.nZ.ToString());
}
Проблема в том, что в примере C # только reading[1]
значимые данные. В примере C оба bird_data[1]
и bird_data[2]
имеют хорошие данные. Как ни странно, reading[2-n]
не все значения обнулены, но кажутся случайными и постоянными. Вот как выглядит вывод из приложения C #:
T:17291325
[30708][-2584][-5220]
[-19660][1048][-31310]
T:17291334
[30464][-2588][-5600]
[-19660][1048][-31310]
T:17291346
[30228][-2600][-5952]
[-19660][1048][-31310]
T:17291354
[30120][-2520][-6264]
[-19660][1048][-31310]
T:17291363
[30072][-2388][-6600]
[-19660][1048][-31310]
Обратите внимание, что верхний триплет каждой записи немного отличается от верхнего триплета записей, предшествующих ей и следующих за ней. В приложении C нижняя строка ведет себя аналогично, но здесь она остается неизменной повсюду.
Может ли это быть связано с отсутствием указания и разыменования? Или я вызываю совершенно неправильное дерево? Я сделал что-то еще, что явно глупо? Самое главное: как мне заставить это работать?
Обновление: Структуры и внешние
C
// Bird reading structure
typedef struct tagBIRDREADING
{
BIRDPOSITION position; // position of receiver
BIRDANGLES angles; // orientation of receiver, as angles
BIRDMATRIX matrix; // orientation of receiver, as matrix
BIRDQUATERNION quaternion; // orientation of receiver, as quaternion
WORD wButtons; // button states
}
BIRDREADING;
// Bird frame structure
//
// NOTE: In stand-alone mode, the bird reading is stored in reading[0], and
// all other array elements are unused. In master/slave mode, the "reading"
// array is indexed by bird number - for example, bird #1 is at reading[1],
// bird #2 is at reading[2], etc., and reading[0] is unused.
typedef struct tagBIRDFRAME
{
DWORD dwTime; // time at which readings were taken, in msecs
BIRDREADING reading[BIRD_MAX_DEVICE_NUM 1]; // reading from each bird
}
BIRDFRAME;
BOOL DLLEXPORT birdGetMostRecentFrame(int nGroupID, BIRDFRAME *pframe);
C#:
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct BIRDREADING
{
public BIRDPOSITION position;
public BIRDANGLES angles;
public BIRDMATRIX matrix;
public BIRDQUATERNION quaternion;
public ushort wButtons;
}
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct BIRDFRAME
{
public uint dwTime;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 127)]
public BIRDREADING[] readings;
}
[DllImport(@"Bird.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool birdGetMostRecentFrame(int nGroupID, ref BIRDFRAME frame);
** Обновление 2: больше структур: **
C
#pragma pack(1) // pack the following structures on one-byte boundaries
// Bird position structure
typedef struct tagBIRDPOSITION
{
short nX; // x-coordinate
short nY; // y-coordinate
short nZ; // z-coordinate
}
BIRDPOSITION;
// Bird angles structure
typedef struct tagBIRDANGLES
{
short nAzimuth; // azimuth angle
short nElevation; // elevation angle
short nRoll; // roll angle
}
BIRDANGLES;
// Bird matrix structure
typedef struct tagBIRDMATRIX
{
short n[3][3]; // array of matrix elements
}
BIRDMATRIX;
// Bird quaternion structure
typedef struct tagBIRDQUATERNION
{
short nQ0; // q0
short nQ1; // q1
short nQ2; // q2
short nQ3; // q3
}
BIRDQUATERNION;
#pragma pack() // resume normal packing of structures
C#
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BIRDPOSITION
{
public short nX;
public short nY;
public short nZ;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BIRDANGLES
{
public short nAzimuth; // azimuth angle
public short nElevation; // elevation angle
public short nRoll; // roll angle
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct BIRDMATRIX
{
public fixed short n[9];
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BIRDQUATERNION
{
public short nQ0; // q0
public short nQ1; // q1
public short nQ2; // q2
public short nQ3; // q3
}
Комментарии:
1. Я не могу сказать, что понимаю, что могут делать все ваши объекты или почему это не приведет к сбою, но большинство массивов основаны на нуле, это определенно должно начинаться с
int k = 1;
?2. Да, это странно, но определенно, начиная с 1. 0 зарезервировано для особого случая, когда запрашивается только одно значение.
3. «0 зарезервировано для особого случая, когда имеется только одно значение» — Значит, если у вас есть 2 элемента, в массиве будет 3 элемента, причем первый элемент с индексом 0 не используется? Если да, то, похоже, над этим следует подумать. Тем более, что индекс 0 уже довольно хорошо обрабатывает «особый случай» массива с одним элементом.
4. Эй, я не писал библиотеку! 😉 Если вы хотите смелости, массив всегда фиксируется на 127. Если подключен только один инструмент и он находится в «автономном» режиме, индексы 1-126 игнорируются. Если, как в моем случае, подключены 2, 0 и 3-126 игнорируются.
5. Мы вынуждены строить догадки без определений структур и некоторого знания того, что за ними стоит
birdGetMostRecentFrame
. Есть ли где-нибудь еще P / Invoke, смешанный где-нибудь?
Ответ №1:
Я попробовал вашу структуру в двух проектах (C / C #), и, кажется, она работает правильно.
Я использую это в C :
#include "stdafx.h"
#include "windows.h"
#pragma pack(1) // pack the following structures on one-byte boundaries
// Bird position structure
typedef struct tagBIRDPOSITION
{
short nX; // x-coordinate
short nY; // y-coordinate
short nZ; // z-coordinate
}
BIRDPOSITION;
// Bird angles structure
typedef struct tagBIRDANGLES
{
short nAzimuth; // azimuth angle
short nElevation; // elevation angle
short nRoll; // roll angle
}
BIRDANGLES;
// Bird matrix structure
typedef struct tagBIRDMATRIX
{
short n[3][3]; // array of matrix elements
}
BIRDMATRIX;
// Bird quaternion structure
typedef struct tagBIRDQUATERNION
{
short nQ0; // q0
short nQ1; // q1
short nQ2; // q2
short nQ3; // q3
}
BIRDQUATERNION;
#pragma pack() // resume normal packing of structures
typedef struct tagBIRDREADING
{
BIRDPOSITION position; // position of receiver
BIRDANGLES angles; // orientation of receiver, as angles
BIRDMATRIX matrix; // orientation of receiver, as matrix
BIRDQUATERNION quaternion; // orientation of receiver, as quaternion
WORD wButtons; // button states
}
BIRDREADING;
#define BIRD_MAX_DEVICE_NUM 126
// Bird frame structure
//
// NOTE: In stand-alone mode, the bird reading is stored in reading[0], and
// all other array elements are unused. In master/slave mode, the "reading"
// array is indexed by bird number - for example, bird #1 is at reading[1],
// bird #2 is at reading[2], etc., and reading[0] is unused.
typedef struct tagBIRDFRAME
{
DWORD dwTime; // time at which readings were taken, in msecs
BIRDREADING reading[BIRD_MAX_DEVICE_NUM 1]; // reading from each bird
}
BIRDFRAME;
extern "C" __declspec( dllexport ) BOOL birdGetMostRecentFrame(int nGroupID, BIRDFRAME *pframe) {
pframe->dwTime = GetTickCount();
for (int i = 0; i < sizeof(pframe->reading)/sizeof(*pframe->reading); i ) {
pframe->reading[i] = BIRDREADING();
pframe->reading[i].position.nX = (short)i;
pframe->reading[i].position.nY = (short)i 1;
pframe->reading[i].position.nZ = (short)i 2;
}
return TRUE;
}
И это в C#:
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BIRDPOSITION
{
public short nX;
public short nY;
public short nZ;
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BIRDANGLES
{
public short nAzimuth; // azimuth angle
public short nElevation; // elevation angle
public short nRoll; // roll angle
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public unsafe struct BIRDMATRIX
{
public fixed short n[9];
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct BIRDQUATERNION
{
public short nQ0; // q0
public short nQ1; // q1
public short nQ2; // q2
public short nQ3; // q3
}
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct BIRDREADING
{
public BIRDPOSITION position;
public BIRDANGLES angles;
public BIRDMATRIX matrix;
public BIRDQUATERNION quaternion;
public ushort wButtons;
}
[StructLayout(LayoutKind.Sequential, Pack = 0)]
public struct BIRDFRAME
{
public uint dwTime;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = 127)]
public BIRDREADING[] readings;
}
public partial class Form1 : Form
{
[DllImport(@"Bird.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern bool birdGetMostRecentFrame(int nGroupID, ref BIRDFRAME frame);
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
BIRDFRAME bf = new BIRDFRAME();
if (checkBox1.Checked)
{
bf.readings = new BIRDREADING[127];
}
if (birdGetMostRecentFrame(0, ref bf)) {
listBox1.Items.Add(bf.dwTime.ToString());
Console.WriteLine(bf.dwTime.ToString());
for (int k = 1; k <= 3; k )
{
var reading = bf.readings[k];
Console.WriteLine(String.Format(" [{0}][{1}][{2}]", reading.position.nX.ToString(), reading.position.nY.ToString(), reading.position.nZ.ToString()));
listBox1.Items.Add(String.Format(" [{0}][{1}][{2}]", reading.position.nX.ToString(), reading.position.nY.ToString(), reading.position.nZ.ToString()));
}
}
}
}
В обоих случаях (чтение, инициализированное как новое в C #, или нет, возвращает значимые данные:
40067905
[1][2][3]
[2][3][4]
[3][4][5]
40068653
[1][2][3]
[2][3][4]
[3][4][5]
40069418
[1][2][3]
[2][3][4]
[3][4][5]
40072585
[1][2][3]
[2][3][4]
[3][4][5]
Сделал это на 64-разрядной версии Windows7.
Я прикрепляю ZIP-файл с обоими проектами для VS2010.
Вот ссылка:
http://hotfile.com/dl/115296617/9644496/testCS.zip.html
Похоже, что вы устанавливаете неправильные значения внутри этой структуры position :/
Комментарии:
1. Хорошо, итак, кажется довольно очевидным, что все маршалируется правильно. Я предполагаю, что проблема должна заключаться где-то еще в приложении C #.
Ответ №2:
Кажется, что sysconf.byNumDevices == 1
so i <= sysconf.byNumDevices
выполняется только один раз, и вы читаете неинициализированные сегменты памяти.
Попробуйте распечатать sysconf.byNumDevices
, и если это 1, попробуйте отследить эту проблему.
Ответ №3:
Массивы в .NET основаны на нуле, а не на единице. Может ли это быть так? Конечно, в .NET также предусмотрена строгая проверка границ, поэтому я ожидал, что ваш «последний» доступ к массиву также завершится ошибкой с исключением.
Не имея доступа к FlockOfBirds
исходному коду, я не уверен, что еще вам сказать.
Комментарии:
1. Я должен был указать, что 0-й элемент пропускается, поскольку он зарезервирован для особого случая. Я полагаю, что массивы C тоже индексируются на 0.
2. Да, массивы c также основаны на 0.
Ответ №4:
Просто мысль: вам действительно нужен ref при переходе к вашему методу?
FlockOfBirds.BIRDFRAME frame = new FlockOfBirds.BIRDFRAME();
FlockOfBirds.birdGetMostRecentFrame(1, ref frame);
Если я не ошибаюсь, то в c # все классы в любом случае передаются по ссылке. Возможно, я злюсь, но разве вы не передаете ссылку на ссылку?
Комментарии:
1. Я действительно помню что-то о том, что все непростые типы передаются через ref, но есть большая разница между передачей через ref и передачей ref.
2. Еще раз подумал об этом, и вот что я нашел: codeguru.com/forum/showthread.php?t=474375 Итак, как насчет того, чтобы попытаться преобразовать DWORD / WORD в int / short, а не в uint / ushort ?