【问题标题】:Could accessing a variable directly (rather than with a pointer and dereferecer) give different values?可以直接访问变量(而不是使用指针和解引用器)给出不同的值吗?
【发布时间】:2011-08-06 14:26:48
【问题描述】:

我知道这是一个奇怪的问题,我冒着表现出我的绿色的风险,但我在这里扯掉了我的头发。

我有一个按预期工作的 C++ 示例。这是一个麻烦的部分的sn-p:

BIRDFRAME frame;
birdGetMostRecentFrame(GROUP_ID,&frame);
BIRDREADING *bird_data;
bird_time=frame.dwTime;
for(FBBloop=FBBstart; FBBloop<FBBend; FBBloop++ )
{                   
    bird_data = &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
}

【问题讨论】:

  • 我不能说我理解你所有的对象可能在做什么,或者为什么这不会导致失败但大多数数组都是从零开始的,这肯定应该以int k = 1; 开头?
  • 是的,这很奇怪,但绝对是从 1 开始。0 保留用于只有一个值要查询的特殊情况。
  • "0 是为只有一个值的特殊情况保留的" - 因此,如果您有 2 个项目,则数组中将包含 3 个元素,而索引 0 处的第一个元素未被使用?如果是这样,似乎应该对此进行一些思考。特别是因为索引 0 已经很好地处理了一项数组的“特殊情况”。
  • 嘿,库不是我写的! ;) 如果你想要胆量,数组总是固定在 127。如果只连接一台仪器并且处于“独立”模式,则索引 1-126 将被忽略。如果像我的情况一样,连接了 2,则忽略 0 和 3-126。
  • 如果没有结构的定义和birdGetMostRecentFrame 背后的一些知识,我们只能猜测。是否也有一些 P/Invoke 混合在某个地方?

标签: c# c++ pointers


【解决方案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# 中读取初始化为 new,或者不返回有意义的数据:

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]

在 Windows7 64 位上完成。 我正在为 VS2010 附加两个项目的 ZIP。

这是链接:

http://hotfile.com/dl/115296617/9644496/testCS.zip.html

您似乎在该位置结构中设置了错误的值:/

【讨论】:

  • 好的,所以很明显一切都被正确编组了。我想问题一定出在 C# 应用程序的其他地方。
【解决方案2】:

似乎sysconf.byNumDevices == 1 所以i &lt;= sysconf.byNumDevices 只循环一次,而您正在读取未初始化的内存段。

尝试打印出sysconf.byNumDevices,如果是 1,请尝试追踪该问题。

【讨论】:

    【解决方案3】:

    .NET 中的数组是从零开始的,而不是从一开始的。会是这样吗?当然,.NET 也有严格的边界检查,所以我预计您对数组的“最后”访问也会失败并出现异常。

    由于无法访问FlockOfBirds 源,我不知道还能告诉你什么。

    【讨论】:

    • 我应该指出第 0 个元素被跳过,因为它是为特殊情况保留的。我相信 C++ 数组也是 0 索引的。
    • 是的,c++ 数组也是基于 0 的。
    【解决方案4】:

    只是一个想法:传递给你的方法时你真的需要 ref 吗?

    FlockOfBirds.BIRDFRAME frame = new FlockOfBirds.BIRDFRAME();
    FlockOfBirds.birdGetMostRecentFrame(1, ref frame);
    

    如果我没记错的话,那么在 c# 中,所有类都是通过引用传递的。我可能很生气,但你不是将 ref 传递给 ref 吗?

    【讨论】:

    • 确实记得所有通过 ref 传递的非简单类型,但是通过 ref 传递和传递 ref 之间有很大的区别。
    • 再想一想,我发现:codeguru.com/forum/showthread.php?t=474375 那么尝试将 DWORD/WORD 编组为 int/short 而不是 uint/ushort 怎么样?
    猜你喜欢
    • 2013-01-14
    • 2017-04-11
    • 1970-01-01
    • 1970-01-01
    • 2019-08-11
    • 2021-12-01
    • 1970-01-01
    • 2023-03-19
    • 1970-01-01
    相关资源
    最近更新 更多