Variable number of parameters such as importing external printf in C # using undisclosed keywords function [2] C # implementation

Source: Internet
Author: User
Tags mscorlib
Http://www.blogcn.com/user8/flier_lu/index.html? Id = 2602647 & run =. 0a0b923

In fact, C # also provides hidden support for vararg type method definition and calling, that is, the _ Arglist keyword.

the following content is the Program Code :

public class unmarshentedcsharp
{< br> [dllimport ("msvcrt. DLL ", charset = charset. ANSI, callingconvention = callingconvention. cdecl)]
extern static int printf (string format, _ Arglist);

Public static void main (string [] ARGs)
{< br> printf ("% S % d", __ Arglist ("flier Lu", 1024 ));
}< BR >}

We can see that the _ Arglist keyword actually plays a role similar to va_list in C ++. It directly pushes any multiple parameters to the stack in order and processes them during the call. At the level of IL code, it is similar to the above example of IL assembly and managed C ++:

The following is the program code:

. Method private hidebysig static pinvokeimpl ("msvcrt. dll" ANSI cdecl)
Vararg int32 printf (string format) cel managed preservesig
{
}

. Method public hidebysig static void main (string [] ARGs) cel managed
{
Il_0033: ldstr "% S % d"
Il_0038: ldstr "flier Lu"
Il_003d: LDC. I4 0x400
Il_0042: Call vararg int32 unmarshentedcsharp: printf (string,
...,
String,
Int32)
}

_ Arglist can be used not only for interoperability with existing code, but also as an equivalent feature of Params in C. However, since C # compiler does not support the semantic level, operations must be performed in a relatively complex way.

the following content is the program code:

using system;
using system. runtime. interopservices;

public class unmarshentedcsharp
{< br> Private Static void show (_ Arglist)
{< br> argiterator it = new argiterator (_ Arglist);

while (it. getremainingcount ()> 0)
{< br> typedreference TR = it. getnextarg ();

console. out. writeline ("{0 }:{ 1}", typedreference. toobject (TR), _ reftype (TR);
}< BR >}

Public static void main (string [] ARGs)
{< br> show (_ Arglist ("flier Lu", 1024);
}< BR >}

Unlike in C ++, The __arglist parameter does not require a leading parameter to determine its starting position in the stack.
Argiterator is a dedicated iterator that supports one-way traversal of the parameter list. For each parameter item, getnextarg returns a typedreference type, which indicates pointing to the parameter.
To understand the implementation principle, you must first introduce the typedreference type.
We know that C # provides many name mappings for CLR built-in value types, such as int32 being mapped to int in C. However, there are actually three CLR types that are not mapped to language-level aliases in C #: intptr, uintptr, and typedreference. These three types are called Native int, native unsigned int, and typedref at the Il level. However, at the level of C #, access can only be done in a similar way through system. typedreference. Among them, typedreference is the most strange.
The description of typedreference in msdn is as follows:

Reference:

Describes objects that contain both a managed pointer to a location and a runtime representation of the type that may be stored at that location.

[Clscompliant (false)]
Public struct typedreference

Remarks

A typed reference is a type/value combination used for varargs and other support. typedreference is a built-in value type that can be used for parameters and local variables.
Arrays of typedreference objects cannot be created. For example, the following call is invalid:

Assembly. Load ("mscorlib. dll"). GetType ("system. typedreference []");

That is to say, the value type typedreference is used to save the managed pointer and Its point to the content type. You can check its implementation code (bclsystemtypedreference. CS: 28) to verify this:

The following is the program code:

Public struct typedreference
{
Private int value;
Private int type;

// Other methods
}

Here, value stores the pointer of the object, and type stores the type handle of the object.
You can use _ Arglist. getnextarg () to return the results, or use the _ makeref keyword to construct the results. For example:

The following is the program code:

Int I = 21;

Typedreference TR = _ makeref (I );

The stored objects and types can be obtained using the _ refvalue and _ reftype keywords.

The following is the program code:

Int I = 32;

Typedreference tr1 =__ makeref (I );

Console. Out. writeline ("{0 }:{ 1}", _ refvalue (TR, INT), _ reftype (tr1 ));

Note that the _ refvalue keyword needs to specify the target typedreference and conversion target type. If the type saved in the structure cannot be implicitly converted to the target type, a conversion exception is thrown. Although typedreference. toobject requires mandatory box target values, it is easier to use.

From the implementation point of view, __refvalue and _ reftype are directly extracted from the content of typedreference, which is the most efficient.

The following is the program code:

Int I = 5;
Typedreference TR = _ makeref (I );
Console. Out. writeline ("{0 }:{ 1}", _ refvalue (TR, INT), _ reftype (TR ));

The above code snippet will be compiled:

The following is the program code:

Il_0048: LDC. i4.5
Il_0049: stloc.0
Il_004a: ldloca. s V_0
Il_004c: mkrefany [mscorlib] system. int32
Il_0051: stloc.1
Il_0052: call class [mscorlib] system. Io. textwriter [mscorlib] system. Console: get_out ()
Il_0057: ldstr "{0 }:{ 1 }"
Il_005c: ldloc.1
Il_005d: refanyval [mscorlib] system. int32
Il_0062: ldind. I4
Il_0063: Box [mscorlib] system. int32
Il_0068: ldloc.1
Il_0069: refanytype
Il_006b: call class [mscorlib] system. Type [mscorlib] system. Type: gettypefromhandle (valuetype [mscorlib] system. runtimetypehandle)
Il_0070: callvirt instance void [mscorlib] system. Io. textwriter: writeline (string,
Object,
Object)

We can see that _ makeref, _ refvalue, and _ reftype are directly implemented through the key words mkrefany, refanyval, and refanytype in the il language. This is done by directly operating the stack, without the implicit box/Unbox operations like typedreference. toobject, which is the most efficient.
The implementation of refanyval in JIT (fjit JIT. cpp: 8361) is as follows:

The following is the program code:

Fjitresult fjit: compilecee_refanytype ()
{

// There shocould be a refany on the stack
Check_stack (1 );
// There has to be a typedref on the stack
// This shoshould be a validity check according to the spec, because the spec says
// That refanytype is always verifiable. However, V1. NET Framework throws verification exception
// So to match this behavior this is a verification check as well.
Verification_check (topope () = typerefany );
// Pop off the refany
Pop_stack (1 );
_ Asserte (offsetof (corinfo_refany, type) = sizeof (void *); // type is the second thing

Emit_win32 (emit_pop_i4 () emit_win64 (emit_pop_i8 (); // just pop off the data, leaving the type.

Corinfo_class_handle s_typehandleclass = jitinfo-> getbuiltinclass (classid_type_handle );
Validity_check (s_typehandleclass! = NULL );
Pushop (optype (typevalclass, s_typehandleclass ));
Return fjit_ OK;
}

From the code above, we can see that JIT does not perform any operations on the stack content when processing the refanyval command, but directly operates the stack.

For more information, see the following:

Uninitialized ented C # types and keywords

Uninitialized ented typedreference

A sample chapter from C # programmers reference-value types

PS: The test shows that the vararg call method is not disclosed in MS, probably because of efficiency considerations. Compared with Params, The vararg call method reduces the speed of pure function calling by an order of magnitude :(
NextArticleWe also discussed this issue and concluded that we should try to use it as little as possible without a last resort.

Why _ Arglist is uninitialized ented

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.