Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/262.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
一条语句中的索引、赋值和增量在C+中的行为不同+;和C#。为什么?_C#_C++_Operators_Indexing_Prefix Operator - Fatal编程技术网

一条语句中的索引、赋值和增量在C+中的行为不同+;和C#。为什么?

一条语句中的索引、赋值和增量在C+中的行为不同+;和C#。为什么?,c#,c++,operators,indexing,prefix-operator,C#,C++,Operators,Indexing,Prefix Operator,为什么这个代码示例在c++和c#中表现不同 [C++示例] int arr[2]; int index = 0; arr[index] = ++index; 其结果将是arr[1]=1 [C#示例] 其结果将是arr[0]=1 我觉得这很奇怪。当然,两种语言必须有一些理由以不同的方式实现它?我想知道什么是C++ > C++ > CLI输出?< /P> < P>在同一个赋值中使用索引和++索引的行为在C++中是未指定的。你不能这么做:写arr[index]=index+1,然后增加变量。在我的机

为什么这个代码示例在c++c#中表现不同

[C++示例]

int arr[2];
int index = 0;
arr[index] = ++index;
其结果将是arr[1]=1

[C#示例]

其结果将是arr[0]=1


我觉得这很奇怪。当然,两种语言必须有一些理由以不同的方式实现它?我想知道什么是C++ > C++ > CLI<强>输出?< /P> < P>在同一个赋值中使用索引和++索引的行为在C++中是未指定的。你不能这么做:写
arr[index]=index+1
,然后增加变量。在我的机器上,我的C++编译器看到了ARR(0)=1,而ARR(1)是未被触动的。< /P> < P>你的C++代码实际上可以做任何事情。代码>arr[索引]=++索引调用未定义的行为。

< P> C++版本的结果不会总是像您调用未定义行为时那样编写。在C++中,如果使用表达式中的变量的值,则该变量也会得到未定义的行为;当该变量也被修改为相同的表达式时,除非读取该值是确定要写入的值的一部分,或者表达式包含读取和写入之间的序列点。
在表达式中,你正在读取<代码>索引< /> >的值,以确定在哪里分配“代码”>“<代码>”的右手边的结果,但是,右子表达式也修改了<代码>索引< /> >

,在C++的情况下,至少通过预递增和使用
index
调用未定义的行为,中间没有序列点。如果在启用警告的情况下将该代码提供给GCC,它会说:

preinc.cpp:6: warning: operation on ‘index’ may be undefined

我猜它在C#中也没有定义,但我不懂这种语言。至少对于C和C++,答案是编译器可以做任何它想要的而不出错,因为你的代码是错误的。不同的编译器(甚至是同一个编译器)也没有义务生成一致的结果。

注意:根据的,行为是严格为C#定义的,所以让我重述一下我的答案

此代码:

arr[index] = ++index;
即使C#编译器确切地知道如何对其求值以及求值顺序,也很难读取。仅出于这个原因,就应该避免

on C#操作符甚至指出这种行为可能是未定义的,尽管Eric指出它不是。事实上,多个文档来源(我相信Eric会有所不同)也表明这可能是最好的选择。

C#中的索引是一种值类型,这意味着您在对其执行操作时返回一个新的值实例

如果您将其想象为一个过程而不是一个操作符,那么该过程将如下所示:

public int Increment(int value)
{
   int returnValue=value+1;
   return returnValue;
}
但是,C++处理对象的引用,因此过程如下所示:

int Increment(int &value)
{
   value=value+1;
   return value;
}

<>注释:如果你在一个对象上应用运算符(比如说重载C++操作符),那么C++的行为就如同C++一样,因为对象类型被当作引用传递。

正如其他人所指出的,这个代码的行为在C/C++中是不明确的。你可以得到任何结果

您的C#代码的行为由C#标准严格定义

当然,两种语言必须有一些理由以不同的方式实现它

嗯,假设你在设计C语言,希望使C++程序员容易学习语言。您会选择复制C++解决这个问题的方法,即不定义它吗?你真的想让非常聪明的开发人员更容易意外地编写代码,而编译器可以根据自己的意思来编写代码吗

C#的设计者并不认为简单表达式的未定义行为是一件好事,因此我们严格定义了这种表达式的含义。我们不能同意每个C++编译器所做的事情,因为不同的C++编译器会给你不同的结果,所以我们不能同意所有的代码。 至于为什么C++设计者认为最好让这样的简单表达式有不确定的行为,那么,你必须问其中一个。我当然可以做出一些猜测,但这些只是有根据的猜测

我写了很多关于这类问题的博客文章;我最近的一篇文章几乎就是你在这里提到的代码。您可能想阅读的一些文章:

C#的设计如何鼓励消除细微缺陷:

在C#中,优先级、结合性和执行顺序之间的关系到底是什么

索引、赋值和增量的副作用按什么顺序发生


这比未指定更糟糕,它实际上是未定义的行为。当然,这是我应该写的(它被指定为未定义;-)当你花了一上午的时间调试时,我不能保持头脑清醒。。。(我甚至在gdb中发现了一个bug!)好奇的是,G++4.4.1的行为类似于C#,设置数组[0]=1。未定义的行为意味着它可以设置
array[1]=1
或设置
array[4711]=42
,擦除硬盘,或者让你秃顶,这取决于调试器是否存在,它是在第42次运行,这取决于月亮的相位,你的女朋友有多喜欢你,或者你是否对你妈妈很不好。说“编译器x,版本y,是这样做的”是没有意义的,因为你永远不知道。()它在C#中有严格的定义。我们不会去做这种疯狂的事情,让简单的表达式没有意义,但编译器无论如何都会接受它们,并做一些疯狂的事情。在这里给我们一些荣誉吧疯狂的生意?Eric可能会在“未定义的行为”的含义出现时重新讨论这个问题。问题是我
int Increment(int &value)
{
   value=value+1;
   return value;
}