ARM编译器6诞生有一段时间了,我们的编译器专家Stefano写了一篇ARM编译器6中相对于其他编译器的优点,原文在这里,下面是翻译
Compiler的主要功能是将源代码转换为机器码,但在项目开发过程中,我们难免会遇到一些错误。
一个好的编译器的一个重要指标就是产生清晰和准确的错误和警告信息。清晰的错误消息可以帮助我们迅速发现代码中的错误,而警告信息是编译器在代码中发现的潜在的问题,这些值得我们的调查。ARM编译器6是基于著名的Clang编译器,该编译器相比于其他工具可以提供更准确的警告和错误信息。我们来看一些例子:
我们来写一个例子代码
#include <stdio.h> int main() { int a = 0, b = 0; if (a = b) { printf("Right\n"); } else { printf("Wrong\n"); } return0; }
我们因为在代码中误将’==’写成了’=’,上面的代码在c语言里面是合法的,但代码里的逻辑错误将使程序失败,我们来看看不同的编译器是怎么帮助开发者发现逻辑错误的
ARM Compiler 5 "main.cpp", line 6: Warning: #1293-D: assignment in condition if (a = b) { ^
ARM Compiler 5
"main.cpp", line 6: Warning: #1293-D: assignment in condition
if (a = b) {
^
ARM Compiler 6 main.cpp:6:11: warning: using the result of an assignment as a condition without parentheses [-Wparentheses] if (a = b) { ~~^~~ main.cpp:6:11: note: place parentheses around the assignment to silence this warning if (a = b) { ^ ( ) main.cpp:6:11: note: use '==' to turn this assignment into an equality comparison if (a = b) { ^ ==
ARM Compiler 6
main.cpp:6:11: warning: using the result of an assignment as a condition without parentheses [-Wparentheses]
~~^~~
main.cpp:6:11: note: place parentheses around the assignment to silence this warning
( )
main.cpp:6:11: note: use '==' to turn this assignment into an equality comparison
==
GCC 4.9 main.cpp: In function ‘int main()’: main.cpp:6:14: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
GCC 4.9
main.cpp: In function ‘int main()’:
main.cpp:6:14: warning: suggest parentheses around assignment used as truth value [-Wparentheses]
你可以从不同的输出看到,ARM编译器6不仅告诉你代码中哪里有错,而且给出了种不同的方法去修正这个错误,警告信息引用了整行代码并且高亮了用户需要注意的部分
模板是C++中一个重要特性,但有时也是在查虫中最头疼的的事情。我们来看看另外一个包含模板的例子
int sum_vector(const std::vector<int> &input) { std::vector<float>::const_iterator i = input.begin(); int sum = 0; for(; i != input.end(); ++i) { sum += *i; } return sum; }
错误的根源在于模板对于需要int型的const_iterator使用了float,我们来看看不同编译器对待错误的反应
ARM Compiler 5 "main.cpp", line 5: Error: #144: a value of type "const int *" cannot be used to initialize an entity of type "const float *" std::vector<float>::const_iterator i = input.begin(); ^
"main.cpp", line 5: Error: #144: a value of type "const int *" cannot be used to initialize an entity of type "const float *"
std::vector<float>::const_iterator i = input.begin();
ARM Compiler 6 main.cpp:5:40: error: cannot initialize a variable of type 'std::vector<float>::const_iterator' (aka 'const float *') with an rvalue of type 'const_iterator' (aka 'const int *') 'std::vector<float>::const_iterator i = input.begin(); ^ ~~~~~~~~~~~~~
main.cpp:5:40: error: cannot initialize a variable of type 'std::vector<float>::const_iterator' (aka 'const float *') with an rvalue of type 'const_iterator' (aka 'const int *')
'std::vector<float>::const_iterator i = input.begin();
^ ~~~~~~~~~~~~~
GCC 4.9 main.cpp: In function ‘int sum_vector(const std::vector<int>&)’: main.cpp:5:56: error: conversion from ‘std::vector<int>::const_iterator {aka __gnu_cxx::__normal_iterator<const int*, std::vector<int> >}’ to non-scalar type ‘std::vector<float>::const_iterator {aka __gnu_cxx::__normal_iterator<const float*, std::vector<float> >}’ requested main.cpp:7:26: error: no match for ‘operator!=’ in ‘i != (& input)->std::vector<_Tp, _Alloc>::end<int, std::allocator<int> >()’ main.cpp:7:26: note: candidates are: In file included from /usr/include/x86_64-linux-gnu/c++/4.7/./bits/c++allocator.h:34:0, from /usr/include/c++/4.7/bits/allocator.h:48, … (additional 98 lines following)
main.cpp: In function ‘int sum_vector(const std::vector<int>&)’:
main.cpp:5:56: error: conversion from ‘std::vector<int>::const_iterator {aka __gnu_cxx::__normal_iterator<const int*, std::vector<int> >}’ to non-scalar type ‘std::vector<float>::const_iterator {aka __gnu_cxx::__normal_iterator<const float*, std::vector<float> >}’ requested
main.cpp:7:26: error: no match for ‘operator!=’ in ‘i != (& input)->std::vector<_Tp, _Alloc>::end<int, std::allocator<int> >()’
main.cpp:7:26: note: candidates are:
In file included from /usr/include/x86_64-linux-gnu/c++/4.7/./bits/c++allocator.h:34:0,
from /usr/include/c++/4.7/bits/allocator.h:48,
…
(additional 98 lines following)
ARM编译器5和6产生的错误信息是自解释,并且明确告诉用户如何去修复这个问题:模板类型的不匹配的问题在错误信息中明确指出,箭头号明确指出了错误点。相比之下,GCC产生了100多行神仙才能看得懂的错误信息。
ARM编译器6中另外一个非常有用的功能就是自动宏展开。考虑下面的代码:
#define LOG(PREFIX, MESSAGE) fprintf(stderr, "%s: %s", PREFIX, MESSAGE) #define LOG_WARNING(MESSAGE) LOG("Warning", MESSAGE) … LOG_WARNING(123); …
LOG_WARNING被传入了一个整型参数,通过展开宏,你发现它其实需要一个字符串。但代码中宏在一起的时候,这些错误很容易发现,但如果这些定义在不同的文件中,甚至来自外部库呢?
ARM编译器6自动展开每个宏,这样你可以很容易在下面看到调用链中的错误:
ARM Compiler 6 main.cpp:8:14: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat] LOG_WARNING(123); ~~~~~~~~~~~~^~~ main.cpp:5:45: note: expanded from macro 'LOG_WARNING' #define LOG_WARNING(MESSAGE) LOG("Warning", MESSAGE) ^ main.cpp:3:64: note: expanded from macro 'LOG' #define LOG(PREFIX, MESSAGE) fprintf(stderr, "%s: %s", PREFIX, MESSAGE) ^
main.cpp:8:14: warning: format specifies type 'char *' but the argument has type 'int' [-Wformat]
LOG_WARNING(123);
~~~~~~~~~~~~^~~
main.cpp:5:45: note: expanded from macro 'LOG_WARNING'
#define LOG_WARNING(MESSAGE) LOG("Warning", MESSAGE)
main.cpp:3:64: note: expanded from macro 'LOG'
#define LOG(PREFIX, MESSAGE) fprintf(stderr, "%s: %s", PREFIX, MESSAGE)
总结
综上我们可以看见ARM编译器6可以给出明确而详细的警告和错误消息,让代码差错工作变得简单。编译器给出高质量的警告和错误提示,不但可以帮助开发发现最终产品潜在的错误,而且可以通过提供容易理解和有意义的建议帮助开发者快速理解和修复错误。
我希望这个博客对你有用,并期望你能用上ARM编译器6!如果你还没有DS-5,可以下载30天试用版
请随意提出你的问题或者在下面评论
Ciao
Stefano