none
ERROR: You can only take the address of an unfixed expression inside of a fixed statement initializer RRS feed

  • Question

  • I have the following class:

    public class WindowInfo { public Int64 PTime = 0; public WindowInfo ( IntPtr PHandle ) { System.Runtime.InteropServices.ComTypes.FILETIME CreationTime, ExitTime, KernelTime, UserTime; if ( ! Win32.GetProcessTimes ( PHandle, out CreationTime, out ExitTime, out KernelTime, out UserTime ) ) return;

    Int64 Test; unsafe { byte *pProcessTime = (byte *) &PTime; *( (int *) pProcessTime ) = CreationTime.dwLowDateTime; *( (int *) (pProcessTime + 4) ) = CreationTime.dwHighDateTime; } } }


    The VS 2017 IDE doesn't like the following and complain of "You can only take the address of an unfixed expression inside of a fixed statement initializer":

    byte *pProcessTime = (byte *) &PTime;

    Can anyone please explain what exactly does this message mean and how do I fix the statement? If I replace &PTime with &Test, it works. Why?

    Monday, July 2, 2018 5:06 AM

Answers

  • Well, it's obvious what that error means. You can't do the cast (byte*) inside the "fixed" statement. In that case, your guess what to do about it is probably as good as mine, but here's mine anyway.

                fixed (void* vp = &PTime)
                {
                      byte* pProcessTime = (byte*)vp;
    
                      *((int*)pProcessTime) = CreationTime.dwLowDateTime;
                      *((int*)(pProcessTime + 4)) = CreationTime.dwHighDateTime;
                }
    

    • Marked as answer by Dev10110110 Monday, July 2, 2018 6:33 AM
    Monday, July 2, 2018 6:19 AM

All replies

  • The error means that the Garbage Collector might decide to move PTime while you are still using pProcessTime, with potentially  disastrous results. The solution is to use the "fixed" keyword to prevent this happening.

        unsafe
        {
          fixed(byte *pProcessTime = (byte *) &PTime)
          {
    
             *( (int *) pProcessTime       ) = CreationTime.dwLowDateTime;
             *( (int *) (pProcessTime + 4) ) = CreationTime.dwHighDateTime;
          }
        }

    https://docs.microsoft.com/en-us/dotnet/csharp/language-reference/keywords/fixed-statement

    I think (not 100% certain) that &Test works because Test is on the stack instead of the heap, so the Garbage Collector won't move it.


    Monday, July 2, 2018 5:51 AM
  • Thanks Ante Meridian. Unfortunately, the error is "The right hand side of a fixed statement assignment may not be a cast expression" for the statement:

    fixed(byte *pProcessTime = (byte *) &PTime);

    Monday, July 2, 2018 6:04 AM
  • Well, it's obvious what that error means. You can't do the cast (byte*) inside the "fixed" statement. In that case, your guess what to do about it is probably as good as mine, but here's mine anyway.

                fixed (void* vp = &PTime)
                {
                      byte* pProcessTime = (byte*)vp;
    
                      *((int*)pProcessTime) = CreationTime.dwLowDateTime;
                      *((int*)(pProcessTime + 4)) = CreationTime.dwHighDateTime;
                }
    

    • Marked as answer by Dev10110110 Monday, July 2, 2018 6:33 AM
    Monday, July 2, 2018 6:19 AM
  • Many thanks Ante Meridian. That does it.

    I do have something similar in other parts of my code. But the expression is so obscure that it could not be retained in my memory.

    I have improved the code a bit to:

    unsafe
    {
      fixed ( void *p = &PTime )
      {
        int *pProcessTime = (int*) p;
        *( pProcessTime++ ) = CreationTime.dwLowDateTime;
        *( pProcessTime ) = CreationTime.dwHighDateTime;
      }
    }


    Monday, July 2, 2018 6:33 AM
  • One more improvement. I am an obsessive reductionist.

    unsafe
    {
      fixed ( void *p = &PTime )
      {
        *( (int*) p++ ) = CreationTime.dwLowDateTime;
        *( (int*) p   ) = CreationTime.dwHighDateTime;
      }
    }


    Monday, July 2, 2018 7:18 AM