Can I get a pointer to a Span?
I have a (ReadOnly)Span<byte>
from which I want to decode a string.
Only in .NET Core 2.1 I have the new overload to decode a string from it without needing to copy the bytes:
Encoding.GetString(ReadOnlySpan<byte> bytes);
In .NET Standard 2.0 and .NET 4.6 (which I also want to support), I only have the classic overloads:
Encoding.GetString(byte bytes);
Encoding.GetString(byte* bytes, int byteCount);
The first one requires a copy of the bytes into an array which I want to avoid.
The second requires a byte pointer, so I thought about getting one from my span, like
Encoding.GetString(Unsafe.GetPointer<byte>(span.Slice(100)))
...but I failed finding an actual method for that. I tried void* Unsafe.AsPointer<T>(ref T value)
, but I cannot pass a span to that, and didn't find another method dealing with pointers (and spans).
Is this possible at all, and if yes, how?
c# .net-standard-2.0 .net-4.6 .net-core-2.1
add a comment |
I have a (ReadOnly)Span<byte>
from which I want to decode a string.
Only in .NET Core 2.1 I have the new overload to decode a string from it without needing to copy the bytes:
Encoding.GetString(ReadOnlySpan<byte> bytes);
In .NET Standard 2.0 and .NET 4.6 (which I also want to support), I only have the classic overloads:
Encoding.GetString(byte bytes);
Encoding.GetString(byte* bytes, int byteCount);
The first one requires a copy of the bytes into an array which I want to avoid.
The second requires a byte pointer, so I thought about getting one from my span, like
Encoding.GetString(Unsafe.GetPointer<byte>(span.Slice(100)))
...but I failed finding an actual method for that. I tried void* Unsafe.AsPointer<T>(ref T value)
, but I cannot pass a span to that, and didn't find another method dealing with pointers (and spans).
Is this possible at all, and if yes, how?
c# .net-standard-2.0 .net-4.6 .net-core-2.1
1
Enter[ReadOnly]Span<T>.GetPinnableReference()
. If using C# 7.3, leveraging this is as simple asfixed (byte* bytes = span)
-- this compiles for .NET 4.5.2, at least, I haven't tested if it will also really work (I only have later frameworks installed).
– Jeroen Mostert
Jan 18 at 14:43
In prior C# versions, you can use the return value ofref GetPinnableReference()
as the argument toUnsafe.AsPointer
. You need at least C# 7.0 to useref
locals.
– Jeroen Mostert
Jan 18 at 14:49
@JeroenMostert This is great, I'm using C# 7.3 and it's working smooth as silk. Do you want to post an answer about it so I can accept it?
– Ray Koopa
Jan 18 at 16:04
With the help of ILSpy, I actually found a more convenient syntax for earlier versions as well. Also not tested, but since the pointers returned are identical I'm going to assume it works.
– Jeroen Mostert
Jan 18 at 16:16
add a comment |
I have a (ReadOnly)Span<byte>
from which I want to decode a string.
Only in .NET Core 2.1 I have the new overload to decode a string from it without needing to copy the bytes:
Encoding.GetString(ReadOnlySpan<byte> bytes);
In .NET Standard 2.0 and .NET 4.6 (which I also want to support), I only have the classic overloads:
Encoding.GetString(byte bytes);
Encoding.GetString(byte* bytes, int byteCount);
The first one requires a copy of the bytes into an array which I want to avoid.
The second requires a byte pointer, so I thought about getting one from my span, like
Encoding.GetString(Unsafe.GetPointer<byte>(span.Slice(100)))
...but I failed finding an actual method for that. I tried void* Unsafe.AsPointer<T>(ref T value)
, but I cannot pass a span to that, and didn't find another method dealing with pointers (and spans).
Is this possible at all, and if yes, how?
c# .net-standard-2.0 .net-4.6 .net-core-2.1
I have a (ReadOnly)Span<byte>
from which I want to decode a string.
Only in .NET Core 2.1 I have the new overload to decode a string from it without needing to copy the bytes:
Encoding.GetString(ReadOnlySpan<byte> bytes);
In .NET Standard 2.0 and .NET 4.6 (which I also want to support), I only have the classic overloads:
Encoding.GetString(byte bytes);
Encoding.GetString(byte* bytes, int byteCount);
The first one requires a copy of the bytes into an array which I want to avoid.
The second requires a byte pointer, so I thought about getting one from my span, like
Encoding.GetString(Unsafe.GetPointer<byte>(span.Slice(100)))
...but I failed finding an actual method for that. I tried void* Unsafe.AsPointer<T>(ref T value)
, but I cannot pass a span to that, and didn't find another method dealing with pointers (and spans).
Is this possible at all, and if yes, how?
c# .net-standard-2.0 .net-4.6 .net-core-2.1
c# .net-standard-2.0 .net-4.6 .net-core-2.1
edited Jan 18 at 16:06
Ray Koopa
asked Jan 18 at 14:19
Ray KoopaRay Koopa
2,69722858
2,69722858
1
Enter[ReadOnly]Span<T>.GetPinnableReference()
. If using C# 7.3, leveraging this is as simple asfixed (byte* bytes = span)
-- this compiles for .NET 4.5.2, at least, I haven't tested if it will also really work (I only have later frameworks installed).
– Jeroen Mostert
Jan 18 at 14:43
In prior C# versions, you can use the return value ofref GetPinnableReference()
as the argument toUnsafe.AsPointer
. You need at least C# 7.0 to useref
locals.
– Jeroen Mostert
Jan 18 at 14:49
@JeroenMostert This is great, I'm using C# 7.3 and it's working smooth as silk. Do you want to post an answer about it so I can accept it?
– Ray Koopa
Jan 18 at 16:04
With the help of ILSpy, I actually found a more convenient syntax for earlier versions as well. Also not tested, but since the pointers returned are identical I'm going to assume it works.
– Jeroen Mostert
Jan 18 at 16:16
add a comment |
1
Enter[ReadOnly]Span<T>.GetPinnableReference()
. If using C# 7.3, leveraging this is as simple asfixed (byte* bytes = span)
-- this compiles for .NET 4.5.2, at least, I haven't tested if it will also really work (I only have later frameworks installed).
– Jeroen Mostert
Jan 18 at 14:43
In prior C# versions, you can use the return value ofref GetPinnableReference()
as the argument toUnsafe.AsPointer
. You need at least C# 7.0 to useref
locals.
– Jeroen Mostert
Jan 18 at 14:49
@JeroenMostert This is great, I'm using C# 7.3 and it's working smooth as silk. Do you want to post an answer about it so I can accept it?
– Ray Koopa
Jan 18 at 16:04
With the help of ILSpy, I actually found a more convenient syntax for earlier versions as well. Also not tested, but since the pointers returned are identical I'm going to assume it works.
– Jeroen Mostert
Jan 18 at 16:16
1
1
Enter
[ReadOnly]Span<T>.GetPinnableReference()
. If using C# 7.3, leveraging this is as simple as fixed (byte* bytes = span)
-- this compiles for .NET 4.5.2, at least, I haven't tested if it will also really work (I only have later frameworks installed).– Jeroen Mostert
Jan 18 at 14:43
Enter
[ReadOnly]Span<T>.GetPinnableReference()
. If using C# 7.3, leveraging this is as simple as fixed (byte* bytes = span)
-- this compiles for .NET 4.5.2, at least, I haven't tested if it will also really work (I only have later frameworks installed).– Jeroen Mostert
Jan 18 at 14:43
In prior C# versions, you can use the return value of
ref GetPinnableReference()
as the argument to Unsafe.AsPointer
. You need at least C# 7.0 to use ref
locals.– Jeroen Mostert
Jan 18 at 14:49
In prior C# versions, you can use the return value of
ref GetPinnableReference()
as the argument to Unsafe.AsPointer
. You need at least C# 7.0 to use ref
locals.– Jeroen Mostert
Jan 18 at 14:49
@JeroenMostert This is great, I'm using C# 7.3 and it's working smooth as silk. Do you want to post an answer about it so I can accept it?
– Ray Koopa
Jan 18 at 16:04
@JeroenMostert This is great, I'm using C# 7.3 and it's working smooth as silk. Do you want to post an answer about it so I can accept it?
– Ray Koopa
Jan 18 at 16:04
With the help of ILSpy, I actually found a more convenient syntax for earlier versions as well. Also not tested, but since the pointers returned are identical I'm going to assume it works.
– Jeroen Mostert
Jan 18 at 16:16
With the help of ILSpy, I actually found a more convenient syntax for earlier versions as well. Also not tested, but since the pointers returned are identical I'm going to assume it works.
– Jeroen Mostert
Jan 18 at 16:16
add a comment |
2 Answers
2
active
oldest
votes
If you have C# 7.3 or later, you can use the extension made to the fixed
statement that can use any appropriate GetPinnableReference
method on a type (which Span
and ReadOnlySpan
have):
fixed (byte* bp = bytes) {
...
}
As we're dealing with pointers this requires an unsafe
context, of course.
C# 7.0 through 7.2 don't have this, but allow the following:
fixed (byte* bp = &bytes.GetPinnableReference()) {
...
}
Pretty cool. I accept this as an answer as it also covers new C# 7.3 syntax.
– Ray Koopa
Jan 18 at 16:18
add a comment |
Try this:
Span<byte> bytes = ...;
string s = Encoding.UTF8.GetString((byte*)Unsafe.AsPointer(ref bytes.GetPinnableReference()),
bytes.Length);
Thanks! I did not seeGetPinnableReference()
anywhere in IntelliSense. However, this did not seem to work forReadOnlySpan<byte>
(it cannot pass it as ref because it is readonly); but it would work for my initial question (only now I realized I have aReadOnlySpan
, sorry!).
– Ray Koopa
Jan 18 at 16:00
@RayKoopa: the reason you couldn't see the method, by the way, is because it was explicitly hidden as feature. This was back when it was calledDangerousGetPinnableReference
; it's since been downgraded to "not actually that dangerous", but the method's still hidden.
– Jeroen Mostert
Jan 18 at 16:21
1
The alternative proposed forReadOnlySpan
is not correct! Storing it in a variable first and taking theref
of that gives you a reference to the localbyte
, not the spanned array. Accessing any element beyond the first this way will give garbage.
– Jeroen Mostert
Jan 18 at 16:25
@JeroenMostert I actually remember that "Dangerous" method name. I didn't follow up on the recent changes, thanks for clearing this up.
– Ray Koopa
Jan 18 at 16:28
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54255888%2fcan-i-get-a-pointer-to-a-span%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
If you have C# 7.3 or later, you can use the extension made to the fixed
statement that can use any appropriate GetPinnableReference
method on a type (which Span
and ReadOnlySpan
have):
fixed (byte* bp = bytes) {
...
}
As we're dealing with pointers this requires an unsafe
context, of course.
C# 7.0 through 7.2 don't have this, but allow the following:
fixed (byte* bp = &bytes.GetPinnableReference()) {
...
}
Pretty cool. I accept this as an answer as it also covers new C# 7.3 syntax.
– Ray Koopa
Jan 18 at 16:18
add a comment |
If you have C# 7.3 or later, you can use the extension made to the fixed
statement that can use any appropriate GetPinnableReference
method on a type (which Span
and ReadOnlySpan
have):
fixed (byte* bp = bytes) {
...
}
As we're dealing with pointers this requires an unsafe
context, of course.
C# 7.0 through 7.2 don't have this, but allow the following:
fixed (byte* bp = &bytes.GetPinnableReference()) {
...
}
Pretty cool. I accept this as an answer as it also covers new C# 7.3 syntax.
– Ray Koopa
Jan 18 at 16:18
add a comment |
If you have C# 7.3 or later, you can use the extension made to the fixed
statement that can use any appropriate GetPinnableReference
method on a type (which Span
and ReadOnlySpan
have):
fixed (byte* bp = bytes) {
...
}
As we're dealing with pointers this requires an unsafe
context, of course.
C# 7.0 through 7.2 don't have this, but allow the following:
fixed (byte* bp = &bytes.GetPinnableReference()) {
...
}
If you have C# 7.3 or later, you can use the extension made to the fixed
statement that can use any appropriate GetPinnableReference
method on a type (which Span
and ReadOnlySpan
have):
fixed (byte* bp = bytes) {
...
}
As we're dealing with pointers this requires an unsafe
context, of course.
C# 7.0 through 7.2 don't have this, but allow the following:
fixed (byte* bp = &bytes.GetPinnableReference()) {
...
}
answered Jan 18 at 16:15
Jeroen MostertJeroen Mostert
17.4k2252
17.4k2252
Pretty cool. I accept this as an answer as it also covers new C# 7.3 syntax.
– Ray Koopa
Jan 18 at 16:18
add a comment |
Pretty cool. I accept this as an answer as it also covers new C# 7.3 syntax.
– Ray Koopa
Jan 18 at 16:18
Pretty cool. I accept this as an answer as it also covers new C# 7.3 syntax.
– Ray Koopa
Jan 18 at 16:18
Pretty cool. I accept this as an answer as it also covers new C# 7.3 syntax.
– Ray Koopa
Jan 18 at 16:18
add a comment |
Try this:
Span<byte> bytes = ...;
string s = Encoding.UTF8.GetString((byte*)Unsafe.AsPointer(ref bytes.GetPinnableReference()),
bytes.Length);
Thanks! I did not seeGetPinnableReference()
anywhere in IntelliSense. However, this did not seem to work forReadOnlySpan<byte>
(it cannot pass it as ref because it is readonly); but it would work for my initial question (only now I realized I have aReadOnlySpan
, sorry!).
– Ray Koopa
Jan 18 at 16:00
@RayKoopa: the reason you couldn't see the method, by the way, is because it was explicitly hidden as feature. This was back when it was calledDangerousGetPinnableReference
; it's since been downgraded to "not actually that dangerous", but the method's still hidden.
– Jeroen Mostert
Jan 18 at 16:21
1
The alternative proposed forReadOnlySpan
is not correct! Storing it in a variable first and taking theref
of that gives you a reference to the localbyte
, not the spanned array. Accessing any element beyond the first this way will give garbage.
– Jeroen Mostert
Jan 18 at 16:25
@JeroenMostert I actually remember that "Dangerous" method name. I didn't follow up on the recent changes, thanks for clearing this up.
– Ray Koopa
Jan 18 at 16:28
add a comment |
Try this:
Span<byte> bytes = ...;
string s = Encoding.UTF8.GetString((byte*)Unsafe.AsPointer(ref bytes.GetPinnableReference()),
bytes.Length);
Thanks! I did not seeGetPinnableReference()
anywhere in IntelliSense. However, this did not seem to work forReadOnlySpan<byte>
(it cannot pass it as ref because it is readonly); but it would work for my initial question (only now I realized I have aReadOnlySpan
, sorry!).
– Ray Koopa
Jan 18 at 16:00
@RayKoopa: the reason you couldn't see the method, by the way, is because it was explicitly hidden as feature. This was back when it was calledDangerousGetPinnableReference
; it's since been downgraded to "not actually that dangerous", but the method's still hidden.
– Jeroen Mostert
Jan 18 at 16:21
1
The alternative proposed forReadOnlySpan
is not correct! Storing it in a variable first and taking theref
of that gives you a reference to the localbyte
, not the spanned array. Accessing any element beyond the first this way will give garbage.
– Jeroen Mostert
Jan 18 at 16:25
@JeroenMostert I actually remember that "Dangerous" method name. I didn't follow up on the recent changes, thanks for clearing this up.
– Ray Koopa
Jan 18 at 16:28
add a comment |
Try this:
Span<byte> bytes = ...;
string s = Encoding.UTF8.GetString((byte*)Unsafe.AsPointer(ref bytes.GetPinnableReference()),
bytes.Length);
Try this:
Span<byte> bytes = ...;
string s = Encoding.UTF8.GetString((byte*)Unsafe.AsPointer(ref bytes.GetPinnableReference()),
bytes.Length);
edited Jan 18 at 15:04
answered Jan 18 at 14:52
mm8mm8
82.9k81831
82.9k81831
Thanks! I did not seeGetPinnableReference()
anywhere in IntelliSense. However, this did not seem to work forReadOnlySpan<byte>
(it cannot pass it as ref because it is readonly); but it would work for my initial question (only now I realized I have aReadOnlySpan
, sorry!).
– Ray Koopa
Jan 18 at 16:00
@RayKoopa: the reason you couldn't see the method, by the way, is because it was explicitly hidden as feature. This was back when it was calledDangerousGetPinnableReference
; it's since been downgraded to "not actually that dangerous", but the method's still hidden.
– Jeroen Mostert
Jan 18 at 16:21
1
The alternative proposed forReadOnlySpan
is not correct! Storing it in a variable first and taking theref
of that gives you a reference to the localbyte
, not the spanned array. Accessing any element beyond the first this way will give garbage.
– Jeroen Mostert
Jan 18 at 16:25
@JeroenMostert I actually remember that "Dangerous" method name. I didn't follow up on the recent changes, thanks for clearing this up.
– Ray Koopa
Jan 18 at 16:28
add a comment |
Thanks! I did not seeGetPinnableReference()
anywhere in IntelliSense. However, this did not seem to work forReadOnlySpan<byte>
(it cannot pass it as ref because it is readonly); but it would work for my initial question (only now I realized I have aReadOnlySpan
, sorry!).
– Ray Koopa
Jan 18 at 16:00
@RayKoopa: the reason you couldn't see the method, by the way, is because it was explicitly hidden as feature. This was back when it was calledDangerousGetPinnableReference
; it's since been downgraded to "not actually that dangerous", but the method's still hidden.
– Jeroen Mostert
Jan 18 at 16:21
1
The alternative proposed forReadOnlySpan
is not correct! Storing it in a variable first and taking theref
of that gives you a reference to the localbyte
, not the spanned array. Accessing any element beyond the first this way will give garbage.
– Jeroen Mostert
Jan 18 at 16:25
@JeroenMostert I actually remember that "Dangerous" method name. I didn't follow up on the recent changes, thanks for clearing this up.
– Ray Koopa
Jan 18 at 16:28
Thanks! I did not see
GetPinnableReference()
anywhere in IntelliSense. However, this did not seem to work for ReadOnlySpan<byte>
(it cannot pass it as ref because it is readonly); but it would work for my initial question (only now I realized I have a ReadOnlySpan
, sorry!).– Ray Koopa
Jan 18 at 16:00
Thanks! I did not see
GetPinnableReference()
anywhere in IntelliSense. However, this did not seem to work for ReadOnlySpan<byte>
(it cannot pass it as ref because it is readonly); but it would work for my initial question (only now I realized I have a ReadOnlySpan
, sorry!).– Ray Koopa
Jan 18 at 16:00
@RayKoopa: the reason you couldn't see the method, by the way, is because it was explicitly hidden as feature. This was back when it was called
DangerousGetPinnableReference
; it's since been downgraded to "not actually that dangerous", but the method's still hidden.– Jeroen Mostert
Jan 18 at 16:21
@RayKoopa: the reason you couldn't see the method, by the way, is because it was explicitly hidden as feature. This was back when it was called
DangerousGetPinnableReference
; it's since been downgraded to "not actually that dangerous", but the method's still hidden.– Jeroen Mostert
Jan 18 at 16:21
1
1
The alternative proposed for
ReadOnlySpan
is not correct! Storing it in a variable first and taking the ref
of that gives you a reference to the local byte
, not the spanned array. Accessing any element beyond the first this way will give garbage.– Jeroen Mostert
Jan 18 at 16:25
The alternative proposed for
ReadOnlySpan
is not correct! Storing it in a variable first and taking the ref
of that gives you a reference to the local byte
, not the spanned array. Accessing any element beyond the first this way will give garbage.– Jeroen Mostert
Jan 18 at 16:25
@JeroenMostert I actually remember that "Dangerous" method name. I didn't follow up on the recent changes, thanks for clearing this up.
– Ray Koopa
Jan 18 at 16:28
@JeroenMostert I actually remember that "Dangerous" method name. I didn't follow up on the recent changes, thanks for clearing this up.
– Ray Koopa
Jan 18 at 16:28
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54255888%2fcan-i-get-a-pointer-to-a-span%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
1
Enter
[ReadOnly]Span<T>.GetPinnableReference()
. If using C# 7.3, leveraging this is as simple asfixed (byte* bytes = span)
-- this compiles for .NET 4.5.2, at least, I haven't tested if it will also really work (I only have later frameworks installed).– Jeroen Mostert
Jan 18 at 14:43
In prior C# versions, you can use the return value of
ref GetPinnableReference()
as the argument toUnsafe.AsPointer
. You need at least C# 7.0 to useref
locals.– Jeroen Mostert
Jan 18 at 14:49
@JeroenMostert This is great, I'm using C# 7.3 and it's working smooth as silk. Do you want to post an answer about it so I can accept it?
– Ray Koopa
Jan 18 at 16:04
With the help of ILSpy, I actually found a more convenient syntax for earlier versions as well. Also not tested, but since the pointers returned are identical I'm going to assume it works.
– Jeroen Mostert
Jan 18 at 16:16