8

This compiles:

string s = "my string";
unsafe 
{
    fixed (char* ptr = s)
    {               
          // do some works
    }
}

This does not:

string s = "my string";
unsafe 
{
    fixed (char* ptr = (char*)s)
    {               
          // do some works
    }
}

error CS0030: Cannot convert type 'string' to 'char*'

I cannot find the spot in the c# spec which allows the first syntax but prohibit the second. Can you help and point out where this is talked about?

6
  • Not sure why this is downvoted - looks like a good question to me; clear about what is expected, clear about the error etc. Looking in the spec now. Commented Sep 24, 2015 at 19:53
  • While Jon is looking at the spec, let me show you the implementation side of things. For short: the CLI kind of lies about the pointer to a string object and gives you the pointer to its first char instead (it also does so for arrays). Special cases in the runtime ;-) Commented Sep 24, 2015 at 19:58
  • 2
    @LucasTrzesniewski I came across this question while researching different implementations of string.GetHashCode() which is different in different versions of BCL and also different in Mono. In some implementation non zero RuntimeHelpers.OffsetToStringData is added to the pointer value before processing. This could mean that whether or not it points to the first character is version dependent. Commented Sep 24, 2015 at 20:02
  • @zespri that's interesting. I was surprised a bit by the implicit addition of OffsetToStringData myself a first (even though it makes sense), but if that's version-dependent it's... scary. Commented Sep 24, 2015 at 20:05
  • @LucasTrzesniewski in Mono in particular OffsetToStringData is added but it always seems to amount to zero. I wonder why. On an unrelated topic if you run GetHashCode on the same string in .net 2.0 .net 4.0 and mono you will get 3 different results. Starting from .net 4.5 you also have UseRandomizedStringHashing from app.config that affects how it's calculated once again. Commented Sep 24, 2015 at 20:31

1 Answer 1

7

It's in section 18.6 of the spec - the fixed statement.

The relevant productions are:

fixed-statement:
  fixed ( pointer-type fixed-pointer-declarators ) embedded-statement

fixed-pointer-declarator:
   identifier = fixed-pointer-initializer

fixed-pointer-initializer:
  & variable-reference
  expression

You're trying to use the expression version. Now, while there isn't a normal "conversion as an expression* from string to char *, the spec calls out the string case, saying that a fixed-pointer-initializer can be:

An expression of type string, provided the type char* is implicitly convertible to the pointer type given in the fixed statement. In this case, the initializer computes the address of the first character in the string, and the entire string is guaranteed to remain at a fixed address for the duration of the fixed statement. The behavior of the fixed statement is implementation-defined if the string expression is null.

So although it looks like you're just performing a normal variable declaration and using an implicit conversion from string to char *, you're really making use of a special case of what the expression in a fixed-pointer-initializer is allowed to be.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.