“C++ void Pointer”和“C# var”之间的区别
Posted
技术标签:
【中文标题】“C++ void Pointer”和“C# var”之间的区别【英文标题】:Difference between "C++ void Pointer" and "C# var" 【发布时间】:2015-01-01 06:49:29 【问题描述】:在学习 C# 时,我想到了这个问题。 void
和 var
有什么区别?
这是我想分享的两个例子:
void * voidInt = (void *) 7;
void * voidChar = (void *) 'F';
void * voidCharArray = (void *) "AbcString";
这是var
的例子:
var varInt = 7;
var varChar = 'F';
var varCharArray = "AbcString";
void
是匿名数据类型吗?
如果是,那么主要是什么
var
和 void
的区别?
有人可以帮我解决这个问题吗?
【问题讨论】:
var
是纯粹的语法糖。编译器尽力隐式推断强类型。就好像,您已经在源代码中指定了特定类型..但懒得自己输入。尝试设置var x = null;
看看有什么不同。
@VikasGupta 它给出了错误:错误Cannot assign <null> to an implicitly-typed local variable
@FaizanRabbani Exactly.. :) 这里的关键部分是“隐式类型的局部变量”,您可以将 null 分配给 void 指针,但对于 var 而言并非如此。因为 var 完全不同..下面的答案和其他cmets已经说得够多了..所以我将跳过其余部分
注意:C# 支持指针,包括 void*
指针 - 在 unsafe
块中。最终,void*
的 C# 等效项是:void*
在 C++11/14 中有一个与 C# 的 var foo = some_expression;
非常相似的类比,那就是 auto foo = some_expression;
。在这两种情况下,变量 foo
都是强类型的,但该类型是在编译时自动从 some_expression
的类型推断出来的(很可能是一个表达式)。
【参考方案1】:
这里的其他答案非常好,但我认为它们并没有清楚地了解基本面。这是您感到困惑的基础知识,所以让我们解决这些问题。
变量是包含值的存储位置。 变量与类型相关联。 局部变量有一个名称。所以voidInt
、voidChar
、voidCharArray
、varInt
、varChar
和varCharArray
都是变量,它们都有类型与他们相关联。每个变量都可以分配该类型的值或产生该类型的值,具体取决于变量是被写入还是读取。
好的,那么现在什么是指针?
一个类型有一个对应的指针类型。 (请注意,在不安全的 C# 中,只有 非托管类型 具有相应的指针类型。)void *
类型是一种特殊的指针类型。
指针是一个值。
T*
类型的指针可以取消引用以生成T
类型的变量。 T*
不能是 void*
。
指针可以显式转换为任何整数类型或从任何整数类型转换,尽管这些操作允许丢失信息并且取决于实现细节。
任何指针值都可以隐式转换为void*
。
任何void*
值都可以显式转换为任何指针类型值。
C# 中的var
是什么?
var
是一种“语法糖”,它告诉编译器从初始值中推断出变量的类型,而不是要求将其写出。
什么是 C# 中的“匿名类型”?
C# 中的某些表达式具有未声明且没有名称的类型;这些被称为“匿名”类型。所以现在我们可以看看你的程序,看看每一行的作用。
void * voidInt = (void *) 7;
voidInt
是void*
类型的变量。分配给它的值是将整数 7 转换为指针,这在任何现代操作系统上几乎肯定是垃圾指针。这段代码本质上是无意义的。
更合理的代码是:
int myInt = 7;
int* intPtr = &myInt;
void* voidInt = intPtr;
这意味着myInt
是一个保存值7
的变量,intPtr
是一个保存指针的变量;当该指针被取消引用时,它会产生变量myInt
。 voidInt
是一个保存任何指针的变量,从intPtr
读取的值是一个指针。所以现在voidInt
和intPtr
都持有一个指向变量myInt
的指针。
void * voidChar = (void *) 'F';
这里也一样。字符F
被视为数字并转换为指针值,存储在变量中。这是不明智的。合理的代码是这样的:
char myChar = 'F';
void *voidChar = &myChar;
但这完全有道理:
void * voidCharArray = (void *) "AbcString";
C++ 中的字符串字面量可转换为 char*
,它是指向第一个字符的存储空间的指针,并且该指针可转换为 void*
。
这个怎么样?
var varInt = 7;
var varChar = 'F';
var varCharArray = "AbcString";
这只是一种愉快的写作方式
int varInt = 7;
char varChar = 'F';
string varCharArray = "AbcString";
每个变量都有其给定的类型,每个赋值都在变量中存储该类型的值。
匿名类型呢?
var anon = new X = 123, Y = 456 ;
这会产生一个匿名类型的变量,其中匿名类型有两个属性 X 和 Y,两者都是 int
类型。该类型没有名称,因此无法在声明中写出类型,因此必须使用var
。
这里的关键是确保您掌握基本原理:指针是值,它们可能被取消引用,这样做会产生一个变量。由于指针是值,它们本身可能存储在指针类型的变量中。这与var
几乎没有任何关系,这是 C# 中一种令人愉快的方式,可以让编译器完成确定变量应该具有什么类型的工作。
【讨论】:
这真是一件好事。真棒@Eric。我想我必须更改正确答案。【参考方案2】:void
和var
没有任何共同之处:
void(用于 C 和 C++ 中的指针变量)表示未指定(不确定)的类型。 void*
在托管 C# 中是不允许的*(尽管一个非常弱的类型,例如 object
引用可能是一个近似值)。通常,void*
类型需要重新转换才能有用。
但是,来自方法/函数的void
返回类型的含义相同
在这两种语言中,这是为了传达 没有返回值(就像 Scala 中的 Unit
)
var
定义了一个 implicitly typed variable - 变量仍然具有强类型,但实际类型是在编译时从右侧推断出来的。
例如
var v1 = "Foo"; // v1 is a string, because it is inferred from the right hand side
var v2 = XDocument.Parse(@"c:\temp\foo.xml"); // v2 is the return type of the function
在使用匿名类型时通常需要var
- 这可能是您在var
和匿名类型之间建立联系的地方:
var v3 = new Name = "Foo", Value = 123; // v3 is strongly typed, anonymous class.
var
对于将变量分配给 LINQ 表达式的返回值特别有用,其中类型可能非常复杂:
var v3 = db.Persons
.Join(db.Cities, p => p.CityId, c => c.Id, (p, c) => new Person = p, City = c)
.GroupBy(pc => pc.City.Name);
* 实际上,这并不完全正确,您可以在 C# 中使用 void* 和 unsafe
编辑
还有一点值得一提,从 C#6 开始,隐式 var
类型只能用于局部变量,即 C# 不支持方法返回类型的隐式类型(与 Scala 等函数式语言不同,其中在大多数情况下,编译器还可以推断方法的返回类型)。
【讨论】:
不,它不是匿名数据类型,它是从 = 右侧返回的类型。例如,var i = 1;
,现在 i
的类型为 int
这是匿名类型:new Amount = 108, Message = "Hello"
但var
将继承右侧的任何类型,是的,在这种情况下它是匿名类型,但并非每次都是匿名的
@FaizanRabbani: C# 中的 var
更接近于 C++ 中的 auto
。在这两种情况下,程序员都不需要指定确切的类型,它是通过使用分配给它的值的类型来推断的。这并不意味着它是匿名的。
@FaizanRabbani: auto
是一个 C++11 特性...你需要使用支持它的编译器并启用它。
@FaizanRabbani C# 也不是 just 静态类型的;见dynamic
;p【参考方案3】:
在不安全的上下文中,C# 中的 C++ void*
等价于 void*
。任何数据指针类型都可以分配给void*
。
在安全的上下文中,object
是(松散地)对应的概念。任何类/接口/结构实例都可以分配给它。
在 C++ 中 C# var
的等价物是 auto
。当用于声明和初始化局部变量时,它充当分配给该变量的表达式的类型(如果可能的话)。
【讨论】:
需要明确的是,int
等原始类型在 C# 中也是结构,因此它们也可以分配给 object
类型的变量。
次要 nitpick... 但函数指针不能(安全地)分配给 void*
这是未定义的行为。就是说 POSIX 需要它,因此大多数编译器都支持它,尽管如果你打开了它们会发出警告。【参考方案4】:
你可以用 c++ void 指针来做到这一点:
void * val = (void *) 7;
val = (void *) "Abcd";
但是你不能用 c# var 做到这一点:
var val = 7;
val = "abcd";
这会引发错误。
更新
如果你想实现void *
的类似行为,可以使用dynamic
。
dynamic val = (dynamic) 7;
val = (dynamic) "ABC";
当使用var
时,变量的实际类型是在编译时确定的。但是,当使用dynamic
时,变量的实际类型是在运行时确定的。
【讨论】:
好的,会的。但是anonymous datatype
是什么?
@FaizanRabbani 仅表示编译器在后台为您创建的类型,您无法通过名称显式引用(它是不可发音的);在这里你必须使用var
、object
或dynamic
之一,因为你没有其他选择:你不能使用实际名称因为你没有'不知道。例如:var foo = new Id = 123, Name = "abc" ;
但那是unsafe
以上是关于“C++ void Pointer”和“C# var”之间的区别的主要内容,如果未能解决你的问题,请参考以下文章
第三十一节:扫盲并发和并行同步和异步进程和线程阻塞和非阻塞响应和吞吐等
shell中$()和 ` `${}${!}${#}$[] 和$(()),[ ] 和(( ))和 [[ ]]
Java基础8---面向对象代码块和继承和this和super和重写和重载和final
Java基础8---面向对象代码块和继承和this和super和重写和重载和final
JS中some()和every()和join()和concat()和pop(),push(),shift(),unshfit()和map()和filter()