再见,机器人--你好,沼泽地。 - 页 7

 
Renat:
...

对这个例子的测试。

  • MQL4/MQL5 - 对潜在的错误给出警告

  • Visual Studio 2012,包括代码分析--什么都没有,对潜在错误的分析质量是零。由于长期以来没有竞争对手,他们就不去理会。

  • PVS工作室 - 报告正确。

  • Lint - 报告同样的事情,但'x'隐藏...

    ...

Pavlick:

我认为这些信息也是绝对无用的。我不是一个专业的程序员,但µl中的这种胡言乱语让我感到压力。我想知道如果对a和b的引用是恒定的,PVS Studio会不会产生一个警告(自己没有办法检查)?

不过,先弄清楚警告的内容,然后引用它作为论据,也不是一件坏事。PVS Studio会警告你,不是因为全局变量 被隐藏了,而是因为a和b是通过非常量引用传递的,但没有被修改。在这种情况下,他们认为a和b应该由一个常数引用来传递。例如,下面的例子并没有让这个分析器抱怨。

int a=1,b=2;
int sum(const int& a, const int& b){
        return(a+b);
}

int main(){
        return sum(a,b);
}

//-------------------------------------------------
int a=1,b=2;
int sum(int& a, int& b){
        ++a; ++b;
        return(a+b);
}

int main(){
        return sum(a,b);
}
 

我很清楚PVS在责备我们什么。

再一次,我们没有编译数十亿行旧C/C++代码的责任负担。这取决于他们自己的编译器,不要因为产生警告而破坏了他们的业务。另一方面,我们对我们的应用语言的安全和错误控制负有责任,它与金钱打交道。

只有百分之几的MQL4/5代码作者是专业(真正意义上的)程序员。剩下的都是自学成才,根本不知道自己写的代码有多糟糕。

例如,在迁移到更新的MQL4之后,我们不得不手动翻阅kodobase中的数千个来源,并修复其旧代码中数量惊人的错误。即使不运行程序,编译器也已经发现并显示了很多错误。

这就是为什么我们不应该提出发布警告的主张,而是要修复自己的代码。

 
Renat:

我很清楚PVS在责备我们什么。

再一次,我们没有编译数十亿行旧C/C++代码的责任负担。这取决于他们自己的编译器,不要因为产生警告而破坏了他们的业务。另一方面,我们对我们的应用语言的安全和错误控制负有责任,它与金钱打交道。

只有百分之几的MQL4/5代码作者是专业(真正意义上的)程序员。剩下的都是自学成才,根本不知道自己写的代码有多糟糕。

例如,在迁移到更新的MQL4之后,我们不得不手动翻阅kodobase中的数千个来源,并修复其旧代码中数量惊人的错误。即使不运行程序,编译器也已经发现并显示了很多错误。

这就是为什么你不应该抱怨发出警告,而应该修复你的代码。


如果数组允许你错过它的范围,那么在编写指标本身时,如果花费与编写指标相当的努力,而只是为了计算开始,那就非常愚蠢了。

你不必去挖掘这些代码,其中一半的代码没有被修复,而是被破坏了。你可以只做一个额外的属性来区分老的mql4,新的mql4或者新的mql4与strict。旧的编译器采取什么尺寸?我不知道,但可能不到一兆字节,在千兆字节的时代,拖着它走是没有问题的。但在这里,我们有一种英雄的行为--破坏代码库。

* * *

警告

声明'a'隐藏了第X行的全局声明

这是一个愚蠢的警告。如果在 "更高 "的世界里有人有问题,并不意味着其他人也可能有这样的问题。变量 是有范围 的,别人叫什么变量是私人问题。

 
Integer:


如果允许一个数组滑过它的范围,那么在编写指标时,做出与编写指标本身相当的努力是非常愚蠢的,而只是为了计算出计算的起点。

你可以不挖这个代码,有一半的代码不是固定的而是坏的。可能只是做了一个额外的属性来区分老的mql4,新的或新的有严格的。旧的编译器采取什么尺寸?我不知道,但可能不到一兆字节,在千兆字节的时代,拖着它到处走没有问题。但这里做了一种英雄式的工作--破坏代码库。

确切地说,是修好了,没有坏。

如果一个错误是在编辑后溜进去的,那是完全有可能的--任何编辑都不可避免地会出现这样的错误。但这并不意味着你可以把单一的错误挂在旗子上,爬上纠正后的山头。


'a'隐藏了第X行的全局声明

这是一个愚蠢的警告。如果 "更高 "的世界中有人有问题,并不意味着其他人也可能有这样的问题。有一个变量可见的区域,任何人称之为变量都是一个私人问题。

令人惊讶的是,人们为自拍的权利而奋斗。特别令人欣慰的是,有人一本正经地写下 "不要管旧的编译器"。
 
simpleton:

潜在的错误就是潜在的错误,因为它根本就不一定是一个错误。

我不知道,我不知道。我们过去有一个经验法则,把4级或5级的认股权证放出来,并勾选把认股权证算作错误。

我们用pragmas摆脱了非常愚蠢的警告,但我们还是摆脱了它们。

 
Andrei01:

这句话毫无意义,原则上没有给程序员提供任何有用的信息,因为并没有像声称的那样,对变量 "a "进行隐藏。

1.cpp(3): remark #3280: declaration hides variable "a" (declared at line 1)
  int sum(int& a, int& b){        

如果程序员故意使用隐藏,那么是的,这句话毫无意义,不能提供任何有用的信息。另一方面,如果隐瞒是由于疏忽而意外完成的,那么该备注可以让我们在早期阶段发现错误。

Andrei01:

只有在创建变量的本地副本时才会发生隐藏,这也是一个完全合法的行为。即使因为这种隐藏而在代码中突然出现错误,也很容易被发现,正是因为搜索立即找到了相同的名字。如果我们开始改变和改动函数模板中的名称,这是编译器逻辑对这一规则的 "解决方案",那么错误搜索的情况将变得更加复杂,在理解代码方面的混乱将比比皆是。这似乎很明显。

局部变量 和参数都在一个作用域中,所以参数是否有这个名字或局部变量并不重要,但在任何情况下这个名字都会在外部作用域中隐藏一个名字。

隐藏与变量的副本没有关系,它与实体名称有关。是的,尽管它与类型等实体名称有关。

class A { };

void f(int a) {
        A x;
}

它的编译。

$ icpc -c 1.cpp
$ 

还有这个。

class A { };

void f(int A) {
        A x;
}

它没有。

$ icpc -c 1.cpp
1.cpp(4): error: expected a ";"
        A x;
          ^

compilation aborted for 1.cpp (code 2)
$ 

因为函数里面的名字A不再是一个类型名,而是一个变量参数名。在外层作用域中声明的类型的名称现在被变量-参数的名称所隐藏。你可以通过发现这段代码来间接窥见这一点

class A { };

void f(int A) {
        A++;
}

编译得很好。

$ icpc -c 1.cpp
$ 

在MQL4++中,在通过变量-参数名称隐藏类型名称的阶段,即即使是空的函数体,这也不会被编译。

#property strict

class A { };
void f(int A) { }
void OnStart() { }

结果。

'A' - structure identifier cannot be used       3.mq4   4       12
'A' - structure identifier cannot be used       3.mq4   4       12

我不知道为什么,但我一点都不惊讶。

另一方面,对于C++来说,这样的代码是没有问题的。

class A { };
void f(int A) { }

编译尝试的结果。

$ icpc -c 1.cpp
$ 

这个例子表明,隐藏与实体名称有关,与其他东西无关。

如果这句话不能切换,我们就得发明各种东西,比如异化。但如果它是可转动的,如英特尔编译器,你就不会有这样的问题。

MQL4++的问题不在于编译器功能本身,即检测嵌套作用域中的隐藏名称,而在于这个功能的基本不可操作性。

 
Renat:

因此,人们不应该对警告提出主张,而应该修复自己的代码。

对所讨论的警告/注解的抱怨,我认为可以是一个--关于它们原则上的不可排除性。

当然,你也不能告诉程序员在语言中该做什么,不该做什么。

 

这样的信息(隐藏全局变量)在C++中就是没有意义的(mql被声明为像C++,对吗?)例如,这就是原因。

struct S1{
    int val;
};

struct S2{};

template<typename _T>
struct SS : _T{
    int f() {int val; return val;}
};

int main(){
    SS<S1> q1; q1.f();
    SS<S2> q2; q2.f();
}
 
Pavlick:

这样的信息(隐藏全局变量)在C++中就是没有意义的(mql被声明为像C++,对吗?)例如,这就是原因。

struct S1{
    int val;
};

struct S2{};

template<typename _T>
struct SS : _T{
    int f() {int val; return val;}
};

int main(){
    SS<S1> q1; q1.f();
    SS<S2> q2; q2.f();
}

这里采取C++,是因为MQL4++没有结构/类模板--只有函数模板?

我不确定开发者是否意识到这一点,但类模板在MQL4++中也是可行的,尽管有很大的限制。特别是,这个例子可以通过以下方式移植到MQL4++中(在一个方法中也使用了一个参数而不是一个局部变量)。

#property strict

struct S1 { };
struct S2 { int val; };

template <typename T>
void f(T &t) {
  struct SS: public T {
    int f(int val) { return val; }
  } ss = {0}; // Переменная типа SS
}

void OnStart() {
  S1 s1; f(s1);
  S2 s2; f(s2);
}

在编译时将会弹出一个关于隐藏名字的警告。

'3.mq4' 3.mq4   1       1
struct has no members, size assigned to 1 byte  3.mq4   3       8
struct has no members, size assigned to 1 byte  3.mq4   8       10
declaration of 'val' hides member declaration at line 4 3.mq4   9       15
0 error(s), 3 warning(s)                1       4

如果OnStart()的最后一行被注释掉,关于隐藏名字的警告就会消失。

 
simpleton:

这里采用C++,是因为MQL4++中没有结构/类模板--只有函数模板?

...

一般来说,是的,但你也可以使用µl。

struct S1{
    int val;
};

struct S2{};

#define INSTANTIATE(_Name, _T)          \
    struct _Name : _T                   \
    {                                   \
        int f() {int val; return val;}; \
    }

INSTANTIATE(SS1, S1);
INSTANTIATE(SS2, S2);

void start(){
    SS1 q1; q1.f();
    SS2 q2; q2.f();
}