“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# 时,我想到了这个问题。 voidvar 有什么区别? 这是我想分享的两个例子:

void * voidInt = (void *) 7;
void * voidChar = (void *) 'F';
void * voidCharArray = (void *) "AbcString";

这是var的例子:

var varInt = 7;
var varChar = 'F';
var varCharArray = "AbcString";
void匿名数据类型吗? 如果是,那么主要是什么 varvoid 的区别?

有人可以帮我解决这个问题吗?

【问题讨论】:

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】:

这里的其他答案非常好,但我认为它们并没有清楚地了解基本面。这是您感到困惑的基础知识,所以让我们解决这些问题。

变量是包含存储位置变量类型相关联。 局部变量有一个名称

所以voidIntvoidCharvoidCharArrayvarIntvarCharvarCharArray 都是变量,它们都有类型与他们相关联。每个变量都可以分配该类型的值或产生该类型的值,具体取决于变量是被写入还是读取。

好的,那么现在什么是指针?

一个类型有一个对应的指针类型。 (请注意,在不安全的 C# 中,只有 非托管类型 具有相应的指针类型。) void * 类型是一种特殊的指针类型。 指针是一个值。 T* 类型的指针可以取消引用以生成T 类型的变量T* 不能是 void*。 指针可以显式转换为任何整数类型或从任何整数类型转换,尽管这些操作允许丢失信息并且取决于实现细节。 任何指针值都可以隐式转换为void*。 任何void* 值都可以显式转换为任何指针类型值。

C# 中的var 是什么?

var 是一种“语法糖”,它告诉编译器从初始值中推断出变量的类型,而不是要求将其写出。

什么是 C# 中的“匿名类型”?

C# 中的某些表达式具有未声明且没有名称的类型;这些被称为“匿名”类型。

所以现在我们可以看看你的程序,看看每一行的作用。

void * voidInt = (void *) 7;

voidIntvoid* 类型的变量。分配给它的值是将整数 7 转换为指针,这在任何现代操作系统上几乎肯定是垃圾指针。这段代码本质上是无意义的。

更合理的代码是:

int myInt = 7;
int* intPtr = &myInt;
void* voidInt = intPtr;

这意味着myInt是一个保存值7的变量,intPtr是一个保存指针的变量;当该指针被取消引用时,它会产生变量myIntvoidInt 是一个保存任何指针的变量,从intPtr 读取的值是一个指针。所以现在voidIntintPtr 都持有一个指向变量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】:

voidvar 没有任何共同之处:

void(用于 C 和 C++ 中的指针变量)表示未指定(不确定)的类型。 void* 在托管 C# 中是不允许的*(尽管一个非常弱的类型,例如 object 引用可能是一个近似值)。通常,void* 类型需要重新转换才能有用。

但是,来自方法/函数的void 返回类型的含义相同 在这两种语言中,这是为了传达 没有返回值(就像 Scala 中的 Unit

相比之下,C# 中的 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 仅表示编译器在后台为您创建的类型,您无法通过名称显式引用(它是不可发音的);在这里你必须使用varobjectdynamic之一,因为你没有其他选择:你不能使用实际名称因为你没有'不知道。例如: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()

malloc和free,brk和sbrk和mmap和munmap的使用和关系以及内存分配的原理