新手用这个,为什么main()运行结果??一个main方法就报这

51CTO旗下网站
Scala初学者学习资料:main(String[])
本文是一位美国开发者在08年初写的Scala学习笔记的第一部分,讲述Scala中的一些基础知识,尤其是main(String[])的用法。
作者:Eastsun来源:| 09:32
51CTO编辑推荐:
你可能已经使用JAVA若干年了,或许JAVA是你接触编程来的第一门编程语言,或许是作为比C++更好的一个选择。不管怎么样,你已经适应了JAVA,并了解她的外观与内在,能够体会它的喜怒与哀乐(原文:You’re comfortable with Java, you know its ins and outs, its moods)。她就像你相处多年的女朋友,或许刚相识时那种激情已经不再,但你已经熟悉怎样才能让她开心。简单的说,如果你是一位工匠,则JAVA就是你干活的工具。
然而,你和JAVA的蜜月期过去了,你在编程语言的选择上更加务实了。只要有足够的理由,你就可以毫不犹豫去尝试一种新的语言,但JAVA还没有足够的缺陷让你下定决心离开她。此时,你听说了一个叫做Ruby的东东,它的简洁优雅以及巨大的威力给你留下深刻的印象。但你并不是那么确定去使用一个脚步语言来构建你的企业应用。动态类型以及TextMate确实都不错,但对于现实世界,你需要一个更坚实的支柱。作为一个实用主义者,你仍然坚持使用JAVA。
这时,好消息传来了。一门新的编程语言登上了舞台并在开发者的世界引起了一场风暴。Scala貌似具有你对一门编程语言所期待一切: 静态类型,编译为字节码,简洁且富有表现力的语法。你可能已经被它的一些例子给深深吸引了。它看起来和JAVA非常相似,但是剔除了JAVA中冗余的语法结构。Scala没有分号,没有public static void的方法修饰词,并且具有静态类型推断机制。
现在剩下的唯一问题就是你应该从何开始。你也许尝试过去Scala的网站查看相关知识,但是。。这一切看起来是那么的函数化:Lamdas,high-order functions,immutable state,recursion out the wazoo。突然让人感到前途未卜。
但是,JavaEE的难民们,不必担心。Scala确实是一门函数式的编程语言,但它同样也是命令式的和面向对象的。也就是说,除了书写那种晦涩难懂的函数式代码(原文: It means that you don’t have to write code with the sole purpose of pleasing Haskell Curry),你还有其它的选择。你可以书写可读性很强的代码,以便你一个星期之后还能看懂它。将你的代码给你那些只使用JAVA的同事看,他们甚至也能看懂它。只需要一个正确的引导,你就可以使用Scala来构建你的的JAVA应用。
如果符合上面所说的,那么这个Scala系列就是为你而准备的。我已经阅读过大量有关Scala的文章以及入门材料(如果你更喜欢函数式的编程,我强烈推荐你去看Alex Blewitt写的系列文章),但很少有文章是为了使JAVA开发比较轻松的转变到Scala来的。我个人缺乏FP(函数式编程)的经验,因此我肯定不会在文章中介绍如何将Scheme代码移植到Scala。该系列文章着重于类比Scala与JAVA,并说明为什么Scala比JAVA更好。
起步: object&HelloWorld&extends&Application{ &&&&&println("Hello,&World!") &}&
没有什么比用代码来获得知识更直接了,注意到上面的代码没有使用分号。当然,如果你愿意还是可以像在JAVA中一样使用它。但除非你想在同一行中书写多个语句,否则分号不是必须的。这个代码示例含义非常清楚,想必你已经看明白了它的功能。没错,就是向标准控制台输出一行"Hello, World!"。你可以将这些代码保存到一个后缀名为scala的文件中,然后使用scala编译器编译它,编译的结果是一个单独的class文件(译者注:这里原文似乎有错,我编译后事实上生成了两个class文件)。你可以像运行普通java文件那样使用java解释器来运行它,不过你需要注意一下classpath。最直接的方法是使用scala命令: scalac&hello.scala& &scala&HelloWorld&
注意到"hello.scala"文件名没有?Scala并不像Java一样强制你在定义public class时,必须保存在文件名与类名相同的文件中。事实上Scala允许你像C++或Ruby一样,在同一个文件中你想定义多少class都可以。但我们最好还是遵循Java的命名规则,因此作为一个具有良好习惯的程序员,我们应该将上面的代码保存为"HelloWorld.scala"。
在刚开始接触Scala,选择一个正确的编辑器是个关键。就像你在使用Java中所了解的那样,IDE非常有用。但作为一门新生的编程语言,Scala目前还没有很好的IDE支持,不过这只是时间问题。在目前,你只有非常有限的选择:
◆Eclipse(有几个不太成熟的Scala插件)
◆IntelliJ(只支持基本的语法高亮)
◆TextMate
(译者注:我使用的是UltraEdit,自己配置一下,能够自动缩进与语法高亮以及编译运行,凑合着用了)
上面列的是几个主要的选项,更完整的列表可以去Scala安装目录下的misc/scala-tool-support/文件夹下查看。我个人推荐使用jEidt或者TextM如果你有冒险精神,可以去尝试Eclipse上的几个插件。Eclipse上的插件具有通常IDE所具有的一些功能(至少Beta版是这样),譬如语义高亮,代码自动完成,etc。但根据我的经验,这些插件都不够稳定以至于难以使用。Scala是一门比Java简洁多的语言,它对IDE的依赖性比Java小得多,因此这些都不是本质问题,你可以照样做的很好。
再来一个例子 object&HelloWorld2{ &&&&&def&main(args:Array[String])&=&{ &&&&&&&&var&greeting&=""&&&&&&&&for(i&&-&0&until&args.length){ &&&&&&&&&&&&greeting&+=&(args(i)&+&"&")&&&&&&&& &&&&&&&&} &&&&&&&&if(args.length&&&0)&greeting&=greeting.substring(0,&greeting.length&-1&) &&&&&&&& &&&&&&&&println(greeting) &&&&&} &}&
(译者注: 可能有读者会奇怪greeting += (args(i) + " ")这段代码为什么要用括号,注意,虽然与习惯不同,但这里的括号是必须的。因为在Scala里面,运算符的优先级由运算符第一个字符代表的运算符的优先级确定。就是说"+="的优先级与"+"的优先级一样,然后……自己想吧:-)。BTW,Scala里的运算符也是方法&对象。)
将它保存到HelloWorld2.scala,并使用如下命令编译运行: scalac&HelloWorld2.scala& &scala&HelloWorld2&Hello,&World!&
这次我们使用了不同的方式,通过命令行向程序传递参数,其运行的结果同样是在控制台输出"Hello, World"。这个程序比上一个复杂一些,首先定义了一个String类型的变量greeting,然后遍历一个数组,最后对String进行适当的处理(Scala专家肯定会建议使用Array#deepMkString(String)(类似于Ruby中的Array::join方法),这样确实没错。但我这里主要是为了介绍一些语言上的知识,而不是API的使用)。
首先应该注意的是,这里我们定义了一个main方法。在第一个例子中,我们仅仅继承了Application类,然后把其它的都交给默认构造函数来做。这样很好很简洁,但有两个问题:第一,我们没有办法向程序传递命令行参数;第二,对Scala新手来说,这样看起来有点魔幻。我将在后面的文章中揭开第一个例子中背后的把戏,现在你记住它就是了。
这个例子中的main方法是不是已经让你联想到了JAVA中的 public static void main?没错,Scala中的main就对应Java中的 public static void main。根据这个信息,有经验的程序员就可以通过思考知道更多关于Scala的知识。
一开始,你可能有这样的结论:Scala中的方法隐含就是public的。这基本正确,Scala中的方法默认为public,这意味着Scala中没有public方法修饰词(private与protected都有定义)。更进一步的,你会猜测:Scala中的方法默认为static的。然而,这次你的猜想不完全正确。
Scala并没有真正意义上的static属性。你越早认识到这一点,你就越容易理解这门语言。作为替代,Scala有专门的语法让你实现与使用sigleton模式(这正是object的含义)。我们实际上声明了一个具有实例方法main(译者注:注意,这个main方法并不是static的)的单实例类(singleton class)。我将会在以后详细说明这一点,目前你可以认为object就是一个只具有静态方法的类。(译者注:这个描述不甚准确)。
仔细的观察这个例子,我们还可以得到Scala中数组的语法,以及如何显式的指明一个变量的类型。让我们仔细研究一下声明main方法的这行代码: def&main(args:Array[String])&=&{&
这儿,args是一个Array[String]类型的方法参数。也就是说,args是一个String数组。在Scala中,Array是一个具有类型参数指明其元素类型的类(一个真正的类,而不是JAVA中那样)。与之对等的JAVA语法应该类似与下面这样子(假设Java中也有一个Array类):public&static&void&main(Array& String&&args)&
在Scala中,使用variable:Type的语法来指明变量类型。因此,如果我们想显式声明一个Int类型的变量,应该通过如下方式 var&myInteger:Int&
在例子中,我们实际上声明了一个String类型的变量greeting。然而,得益于Scala中的类型推断机制,我们并没有显式指明变量的类型。下面两种方式在语义上是等价的: var&greeting&=""&&var&greeting:String&=""&
在第一种方式中,我们显然知道greeting是一个String,Scala编译器也能够推断出这一点。这两个变量都是静态类型检查的,只不过第一种方式可以少写7个字符:-)
细心的读者可能还注意到了,例子中的main方法并没有指明返回类型。这是因为Scala同样可以推断出来。如果我们想显式的指明这点,可以像下面这样:def&main(args:Array[String]):Unit&=&{&
如前面一样,类型在方法名之后,并用冒号隔开。顺便提一下,Unit是Scala中的一个类型,它表示"我不关心返回的究竟是什么东东"(原文:I-really-don't-care-what-I-return),你可以把它想象为JAVA中void类型与对象的混合物(译者注:但Unit不是void,而是一个实实在在的类,也就是说Unit类型的方法会返回一个Unit对象)。
数组的遍历: var&greeting&=""&for(i&&-&0&until&args.length)&{ &&&&&greeting&+=&(args(i)&+&"&") &} &
(译者注: 目前Scala中这种方式遍历的性能相对低下,速度大概是JAVA中对应for的1/60。这个其实也不会造成太大的影响,因为耗时一般不在于for循环本身,而是循环体内的操作。更何况在Scala中用for的机会不多,有更多简单实用的方式去实现同样的操作)
这段代码比刚才那段稍微复杂点。我们一开始声明了一个String类型的变量greeting,然后使用了一个在Scala中不常用的for循环,这里有一些隐含的类型推断。有Ruby经验的知道在Ruby中的等价形式: for&i&in&0..(args.size&-&1) &&&greeting&+=&args[i]&+&"&"&end&
问题的关键在于,Scala的for循环语句需要一个Range对象,而这个Range对象是由RichInt的until方法建立的。我们可以把上面的代码分开写: val&range&=0.until(args.length) &for(i&&-&range)&{&
注意,这里使用"val"而不是"var"声明变量。使用val,就如java中final的语义,指明range是一个常量。
在Scala中,我们可以通过多种不同的形式调用方法。在这个例子中,我们看到了"value methodName param"与"value。methodName(param)"这两种形式的语法是等价的。另外一个很重要的事情是,until方法是RichInt具有的,Int并没有该方法。这里存在一个隐式类型转换,将Int类型的0转换为scala。runtime。RichInt的一个实例。这里不去深究这个类型转换是怎样进行的,我们关心的是RichInt类确实有一个返回Rangle对象的until方法。
因此,事实上这段代码与JAVA中的下列代码在逻辑上是等价的: for&(int&i&=&0;&i&&&args.&i++)&{&
只不过在JAVA中是显式的遍历整个区间,而Scala中使用了一个Range对象。
可能你还注意到了,循环体中访问数组args元素使用的是圆括号"()",而不是我们习惯的方括号"[]"。
更好的遍历方式:
在JAVA 5中引入了一个foreach的语法,像下面这样: for(String&arg:&args)&{ &&&&&greeting&+=&arg&+&"&"; &}&
这样更简洁明了。Scala中使用高阶函数(使用函数做参数的函数)实现类似的功能:args.foreach&{arg&=& &&&&&greeting&+=&(arg&+&"&") &}&
我们可以看到,Array类有一个foreach方法,这个方法将一个函数作为参数。foreach方法将会对Array里的每一个元素调用一次这个函数,并在调用的时候将这个元素作为函数参数传递给函数。这里参数arg没有指明类型,但由于我们是对一个String数组遍历,编译器能推断出它的类型是String。我们已经提到过,Scala中调用方法有多钟不同的方式。这里我们就省略了圆括号"()",同样我们也可以写成: args.foreach(arg&=&&{ &&&greeting&+=&(arg&+&"&") &})&
Scala中我们可以使用更加简洁的书写方式: args.foreach(arg&=&&greeting&+=(arg&+&"&"))&
不错吧,现在我们将整个例子重写成: object&HelloWorld2&{ &&&def&main(args:Array[String])&=&{ &&&&&var&greeting&=&""&&&&&args.foreach(arg&=&&greeting&+=&(arg&+&"&")) &&&&&if&(args.length&&&0)&greeting&=&greeting.substring(0,&greeting.length&-&1) && &&&&&println(greeting) &&&} &}&
Scala的内置类型:
因为Scala是基于JVM的,因此它从JAVA那儿继承了大量的API。这意味这你能够与JAVA交互使用。并且,你所写的Scala代码事实上使用的就是Java API。比如上面的HelloWorld2中我们使用了一个字符串变量greeting,这个变量事实上就是Java中的String类型。再比如,当你在Scala中声明一个整数类型(Int),编译器会自动将它转换为Java的基本类型int。
Scala还内置了一些隐式类型转换,当需要的时候编译器会自动进行(就像例子中的Int到RichInt类型的转换)。比如在Scala中将Array[String]类型传递给需要String[]类型参数的函数时,隐式类型转换就会发生。甚至Scala中的类型参数可以和Java中的泛型相互转化。简单的说,Scala就是一个披着不同语法外衣的Java。
Scala不需要复杂高深的理论或学术知识。一个普通的开发者就可以在下一个企业WEB应用里面使用它。它具有JAVA所缺乏的简洁明了的语法,并且保留了JAVA的高效与可靠性。
【相关阅读】
【责任编辑: TEL:(010)】
大家都在看猜你喜欢
热点头条关注头条关注
24H热文一周话题本月最赞
讲师:415005人学习过
讲师:51311人学习过
讲师:153363人学习过
精选博文论坛热帖下载排行
本书讲述怎样把UNIX环境下的应用程序移植到Linux环境上运行,是一本综合的开发和解决问题的参考手册 。本书详细描述了当前IT行业中被广泛应...
订阅51CTO邮刊java中的main函数为什么是静态的_百度知道
java中的main函数为什么是静态的
答题抽奖
首次认真答题后
即可获得3次抽奖机会,100%中奖。
dayfm2013知道合伙人
来自电脑网络类芝麻团
采纳数:49
获赞数:142
参与团队:
main函数其实也是所在类的一个方法,就比如一个类是test,那么该类的main其实就是test.main(String[] args),众所周知如果一个方法不是静态的,则要先实例化该类,比如要这样
A a=new A();然后才能调用 a.main();
而这对于运行一个程序的主函数来说是不现实的,所以比如把main函数定义为static,使a.main()可以直接被调用。 因此,java规定了main函数必须是静态的
impkfan知道合伙人
采纳数:60
获赞数:227
非静态成员函数在执行前必须先构造并实例化该函数所在的类。如果允许非静态的main,那么main函数所在的类必须先进行实例化,那么就需要再写个函数去实例化main所在的类,再调用main,这个实例化代码又写在哪呢?如果它也是非静态的,岂不是又要写个函数去实例化它所在的类嘛?因此,JAVA语言就规定了main必须是静态的。
本回答被网友采纳
hc知道合伙人
来自电脑网络类芝麻团
采纳数:42
获赞数:61
参与团队:
入口方法如果是非静态的,你如何调用?
匿名用户知道合伙人
来自电脑网络类芝麻团
JAVA语言标准规定
其他1条回答
为你推荐:
其他类似问题
您可能关注的内容
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。IAR里面无法执行到main函数 - ARM技术论坛 -
中国电子技术论坛 -
最好最受欢迎电子论坛!
后使用快捷导航没有帐号?
IAR里面无法执行到main函数
<div class=""
本帖最后由 hubeigaokao 于
22:08 编辑
我是ARM新手,在IAR下开发LPC4300的串口程序,用的都是官方的函数库,在用Jlink调试中一直无法进入main()函数,SystemInit()其实就是一个初始化时钟以及FPU的代码,但程序总是在某行原地打转,如fpu_init()中的Mvfr1 = *regMvfr1; 代码应该没有问题,都是官方函数,可能是硬件有问题吗?& & 请大侠帮忙看一下,附件是相关代码,非常感谢,在线等!
void fpuInit(void)
{
// from arm trm manual:
//& && && && && & ; CPACR is located at address 0xE000ED88
//& && && && && & LDR.W R0, =0xE000ED88
//& && && && && & ; Read CPACR
//& && && && && & LDR R1, [R0]
//& && && && && & ; Set bits 20-23 to enable CP10 and CP11 coprocessors
//& && && && && & ORR R1, R1, #(0xF && 20)
//& && && && && & ; Write back the modified value to the CPACR
//& && && && && & STR R1, [R0]
& && && && && &
& & volatile uint32_t* regCpacr = (uint32_t*) LPC_CPACR;
& & volatile uint32_t* regMvfr0 = (uint32_t*) SCB_MVFR0;
& & volatile uint32_t* regMvfr1 = (uint32_t*) SCB_MVFR1;
& & volatile uint32_t C
& & volatile uint32_t Mvfr0;
& & volatile uint32_t Mvfr1;& &
& & char vfpPresent = 0;
& & Mvfr0 = *regMvfr0;
& & Mvfr1 = *regMvfr1;
& & vfpPresent = ((SCB_MVFR0_RESET == Mvfr0) && (SCB_MVFR1_RESET == Mvfr1));
& &
& & if(vfpPresent)
& & {
& && &&&Cpacr = *regC
& && &&&Cpacr |= (0xF && 20);
& && &&&*regCpacr = C& &// enable CP10 and CP11 for full access
& & }
下载积分: 积分 -1 分
3.61 KB, 下载次数: 0, 下载积分: 积分 -1 分
fpu初始函数
下载积分: 积分 -1 分
9.25 KB, 下载次数: 2, 下载积分: 积分 -1 分
LPC启动代码
下载积分: 积分 -1 分
3.21 KB, 下载次数: 0, 下载积分: 积分 -1 分
系统初始化函数
21:42:23  
该类别下有 16 个回答。
该类别下有 16 个回答。
该类别下有 13 个回答。
该类别下有 9 个回答。
该类别下有 8 个回答。
该类别下有 7 个回答。
该类别下有 7 个回答。
该类别下有 7 个回答。
该类别下有 6 个回答。
该类别下有 6 个回答。
该类别下有 6 个回答。
该类别下有 6 个回答。
该类别下有 6 个回答。
该类别下有 6 个回答。
该类别下有 5 个回答。
该类别下有 5 个回答。
该类别下有 5 个回答。
该类别下有 5 个回答。
该类别下有 5 个回答。
该类别下有 5 个回答。
本帖最后由 hubeigaokao 于
22:00 编辑
各位高人还望解答一下,网上找了一天的解答,还是没搞定。手头这个板子还没跑通过代码,不知道可能的问题在哪?芯片上电就很烫。
有大神知道的吗?还是我发错板块了
你正在撰写答案
如果你是对答案或其他答案精选点评或询问,请使用“评论”功能。
Powered by
供应链服务
版权所有 (C) 深圳华强聚丰电子科技有限公司Visual&C++&2010中初学者常见错误、警告和问题
这部分将帮助大家解释一些常见的错误、警告和问题,帮助大家去理解和解决一些常见问题,并了解它的根本原因。
&iostream.h&与&iostream&
下面的代码为什么在VC2010下面编译不过去?
#include &iostream.h&
int main()
cout&&"Hello
错误信息:fatal error C1083:
无法打开包括文件:“iostream.h”: No such
file or directory
造成这个错误的原因在于历史原因,在过去C++98标准尚未订立的时候,C++的标准输入输出流确实是定义在这个文件里面的,这是C风格的定义方法,随着C++98标准的确定,iostream.h已经被取消,至少在VC2010下面是这样的,取而代之的是我们要用头文件来代替,你甚至可以认为是这样定义的:
namespace std
&&&&&&&&&&&&&
#include "iostream.h"
因此我们可以简单的修改我们的Hello World。
#include &iostream&
int main()
cout&&"Hello
&&&&&iostream.h是属于C++的头文件,而非C的,因此标准订立的时候被改成了。而C的头文件stdio.h等依然可以继续使用,这是为了兼容C代码。但是它们依然有对应的C++版本,如 等。记住,在VC2010上面采用C++风格的头文件而不是C风格的头文件,除非你是在用C。
warning C4996
这是一个警告,请看下面的代码:
&iostream&
int main()
char sz[128] = {0};
strcpy( sz, "Hello World!" );
&&&&上面的strcpy会产生这个警告:
&&&&warning
C4996: 'strcpy': This function or variable may be unsafe. Consider
using strcpy_s instead. To disable deprecation, use
_CRT_SECURE_NO_WARNINGS. See online help for details.
&&&&这是因为VC从2005版本开始,微软引入了一系列的安全加强的函数来增强CRT(C运行时),这里对应的是strcpy_s。_s意为safe的意思,同样的道理,strcat也是同样。因此要解决这个问题,我们可以用strcpy_s来替换strcpy,但是注意strcpy_s并非所有编译器都提供,因此如果要跨编译器,请采用错误信息中所提示的方式,定义_CRT_SECURE_NO_WARNINGS宏来掩耳盗铃吧。另外注意并非所有的加强函数都是在屁股后面加_s,比如stricmp这个字符串比较函数的增强版名字是_stricmp。下面,用strcpy_s来更改程序:
int main()
char sz[128] = {0};
strcpy_s( sz, "Hello World!" );
char* pSz2 = new
char[128];
strcpy_s( pSz2, 128, "hello");
cout&& pSz2
delete pSz2;
&&&&注意,strcpy_s有两个版本,一个可以帮助我们自动推断缓冲区的大小,而另外一个不能帮助我们推断,因此在编译器不能推断缓冲区大小的时候,我们需要自己指定缓冲区的大小,如上面的程序所演示的那样,关于增强版的函数请参考我写的《深入学习C++ String2.1版》。
&&&&&TCHAR、wchar_t、char
&&&&请大家看下面这个程序:
&iostream&
#include &Windows.h&
#include &tchar.h&
int main()
MessageBox( NULL, "你好HelloWorld!", "Information", 0 );
&&&&&貌似没什么问题吧?错了,如果你是按照我教你的方法创建的控制台空工程的话,那么会有编译错误:
C2664: “MessageBoxW”: 不能将参数 2 从“const char [17]”转换为“LPCWSTR”
&&&&&这个问题太普遍了,几乎所有的初学者都会遇到而且感到难以应付,因为按照提示使用(LPCWSTR)强制转型貌似并不能帮助我们解决问题,而且这个程序在VC6下面应该是没有任何问题的,那问题出现在哪里呢?问题在这里,请右键单击解决方案浏览器下面的项目,属性,
问题的根本就是字符集问题,在VC6中,我们默认使用的是多字节字符集,而现在我们默认需要的是UNICODE字符集,简单的,我们把这个字符集改成多字节字符集这个问题就解决了:
再试试应该就可以了吧?但是我并不推荐大家这么做,因为让自己的程序适应各种字符集是我们写代码的人义不容辞的义务。
我们把程序改成下面这样:
&iostream&
#include &Windows.h&
#include &tchar.h&
int main()
MessageBox( NULL, TEXT("你好HelloWorld!"), TEXT("Information"), 0 );
MessageBox( NULL, _T("你好HelloWorld!"),
_T("Information"), 0 );
用两个宏TEXT或者_T都可以解决这个问题,它们两个并没有太大区别,也许区别在于前者是通过windows.h头文件引入的,而_T是通过tchar.h引入的,我推荐大家使用_T和tchar.h,因为tchar.h还帮助我们引入了其它一些很有用的宏,比如_tcscpy_s,这个宏在使用UNICODE字符集的时候被替换成wcscpy_s,在使用多字节字符集的使用被替换成strcpy_s。关于这部分的内容,请大家不要错过《Windows核心编程》的第二章(第四版或第五版都可以),以及《深入学习C++ String2.1版》。 它们都有提到。
有人听说_T可以把多字节字符串转换成UNICODE,因此他写了如下的代码:
const char* pStr =
"haha哈哈";
MessageBox( NULL, _T(pStr), _T("Information"), 0
当然,除非你运气好的抓狂,否则你是编译不过去的,为什么呢?我们现在应该知道对于"Hello"这样的字符串,VC2010会默认的将它视为const char*,即多字节字符串,而L"Hello"前面有个L前缀的被视为UNICODE字符串,这和C#是有区别的,因为C#的字符串总是被视为UNICODE,C++/CLI下面编译器也会帮助我们做到这件事情,所以它们不需要L(C++/CLI兼容L这种写法)。
让我们看看_T的定义吧:
#define wxCONCAT_HELPER(text, line)
text ## line
#ifndef _T
#if !wxUSE_UNICODE
#define _T(x) x
#define _T(x) wxCONCAT_HELPER(L, x)
_T在UNICODE下面最终会被替换成L ## x。 ##是一个编译预处理指令,意味着让L和x贴在一起,比如L ##
"Hello"最终就是L"Hello",因此它可以把"Hello"转换成UNICODE字符串。那为什么上面的程序不行呢?让我们看看_T("pStr")会被替换成什么:L ## pStr -& LpStr,哦,LpStr是一个新的标识符,如果你没有定义过它,你当然不能通过编译啦。
因此我们可以了解到_T这样的宏只能处理直接的常量字符串,不能处理其它的情况。而我们上面演示的那种情况需要我们动态的去转换编码,Windows有API可以帮助我们做到,C库也有函数可以帮助我们。恰好我曾经写过这样的代码,欢迎大家参考:ASCII/UNICODE/UTF8字符串互相转换的C++代码
对于_T宏,再说一点东西,或许你会感到奇怪为什么_T不直接定义成#define _T(x) L ## x,而要绕个圈子去调用wxCONCAT_HELPER呢?这实际上涉及到宏展开顺序和截断的问题。在这里,我们需要说一个宏参数的概念,这很函数的参数是类似的,这里_T(x)的x就是宏参数,好,记住下面一句话:
如果你定义的宏中使用了#或者是##的话,宏参数将不会被展开,也就是说_T(x)如果直接定义成L##x那么在下面这种情况就会出错( PS: #是给参数加引号的意思):
_T(__FUNCTION__),__FUNCTION__是一个预定义的宏,它代表了当前函数的名字,这个展开会是什么呢?L__FUNCTION__。为什么间接调用wxCONCAT_HELPER就能得到正确的结果呢?因为当我们调用wxCONCAT_HELPER的时候,__FUNCTION__已经被_T展开成了函数名。
说多了说多了,如果你觉得复杂可以暂时跳过这些东西,我只是顺便说说。
重定义的编译错误和链接错误
让我们在项目里面再添加一个Test.h头文件,方法是右击解决方案中的项目,添加,新建项,C++头文件,名称输入test.h。然后我们在test.h中输入:
void print()
回到main.cpp中:
&iostream&
#include "Test.h"
#include "Test.h"
int main()
编译一下我们会得到重定义的编译错误:
&&&&&&&&&&&
error C2084: 函数“void print(void)”已有主体
或许你会说,你引用(#include)了两次,我没你那么傻,我只引用一次不就好了么?是的。你聪明,但是是小聪明哈,因为你不能保证每个人都不去引用它。
这个问题演示的是#pragma
once的用处,让我们解开它的注释。编译成功!#pragma once的作用就在于防止头文件被多次引用。你或许见过
#ifndef __TEST_H__
#define__TEST_H__
这样的代码,它们的作用是一样的,如果你跟我一样懒,那么就用#pragma
once,如果你打算去没有这个指令的编译器上编译代码,那么还是用后面一种方式吧。
现在让我们来见识一个对初学者稍微复杂一点的链接错误,用创建main.cpp的方法再添加一个test.h头文件,输入#include "Test.h"即可。
让我们再编译一次。
1&test.obj : error
LNK2005: "void __cdecl print(void)" (?print@@YAXXZ)
Main.obj 中定义
1&e:\documents\visual studio
2010\Projects\HelloWorld\Debug\HelloWorld.exe : fatal error
LNK1169: 找到一个或多个多重定义的符号
如果说编译错误好找的话,链接错误对于初学者来说就有点麻烦了,聪明的初学者会去Google、百度寻找答案,笨的初学者就会找所谓的高手、前辈问,而这些高手Or前辈未必有心情为你解释。要解决这个错误有无数种方法。
1.内联,把print声明为内联函数。
inline void print()
&&&&&&&&&&
这个方法的好处是简单,坏处是局限性太强,意味着你总是需要公开print的实现,因为内联函数必须在编译时就知道实现才行。
2.static,把print声明为static函数:
static void print()。
这便告诉编译器,哥是唯一的,而且哥只能被本编译单元的代码调用,这和extern是对应的。简单来说,想要哥帮你做事,请先include哥声明的头文件,也就是#include "test.h"。
3..h头文件中只放声明,实现放到.cpp中去。
现在test.h中只有void print();,而实现在test.cpp中:
#include "Test.h"
void print()
&&&&&&&&&&&&
int a = 1;
&&&&&&&&&&&
cout&& a++
这个时候有意思的是我们在main.cpp无需包含test.h头文件也可以引用print函数,因为print并非static的函数:
void print();
int main()
但是声明一下是必须的。
工程Setup发布:
1、制作安装文件的过程中,一般会出现几个warning,都是说某dll文件是系统自带的,不用加入安装包中之类的。建议把这些dll从你生成的filesystem中删除,否则有可能遇到系统版本问题。我遇到的相关具体问题是在win7下做的安装包到了xp下就无法安装和运行了。
2、关于快捷方式。我采用的方法是(不知道算不算一种猥琐的方法):先将你编译好的Realse文件夹下面的exe文件添加到你的file
system里。然后右键file
system里添加好的exe文件,会看到生成快捷方式的选项。生成快捷方式后,再将快捷方式剪切复制到user desktop等文件夹中去。
3、Logo。自己画,或者找个bmp转ico文件的转换器吧。不过转换完之后的效果都不怎么理想,毛刺挺多,需要进一步修改。
4、.最后,添加进来的依赖dll有一个选项,选择selfregister的话是可以在安装时刻自动注册的。另外,不要忘了将注册时需要用到的dll也包含进来。
5、.默认安装路径等,在setup工程的property里都可以调整。
主函数main
在VC++编程中,我随便选择了一个以前的程序准备编译,结果报错。一开始怀疑我自己的问题,于是写了一个最简单的程序,还是报错,如下:
好奇下,决定用微软自己的用例跑跑。于是新建了一个工程,并且选择Precompiled header,生成的工程如图:
这时恍然大悟,原来是入口函数有问题。正在做茅塞顿开状,一个学长提醒我到,从VS2005,微软定义的入口函数就是_tmain了,听了我还不相信,因为自己从来都是用main在VS2008中通过编译的。后来在VS2008中生成工程,果然如学长所说。正在郁闷中,学长又提醒我可以设置工程的预编译项,于是自己试了试,果然成功了,在改了以后的设置中,VS2010也可以跑通了。
方法如下:*代表当前工程名
project -&& properties
-&(选择Configuration
Properties,这个时候在顶部的Configuration选择Active(Debug),
再到Configuration
Properties中选择)C/C++
-& Precompiled Header -& Precompiled
Header值改为Use(/Yu),OK了!
总结:VS2008及以前的配置中,默认都是选择了类似的配置,VS2008中是:Use Precompiled Header (/Yu)
中怎么写个简单的C++程序?
#include &iostream&
void main(void)
count&&"hi";
在vs2010中编写以上程序
2&IntelliSense: identifier "count" is
undefined&c:\users\shiechian\documents\visual
2010\projects\test\test\test.cpp&4&2&test
运行结果:
1&------ Build started: Project: test,
Configuration: Debug Win32 ------
1&c:\users\shiechian\documents\visual studio
2010\projects\test\test\test.cpp(4): error C2065: 'count' :
undeclared identifier
========== Build: 0 succeeded, 1 failed, 0 up-to-date, 0
skipped ==========
还出现这个
这是什么原因?
相关答复:
cout写错了,同时还没有添加名字std(标准c++里是需要的,vc6与标准不符,后来新版的vs都与标准一样了)
#include &iostream&
void main(void)
cout&&"hi";
vs 2010中VC++的6个新特点
一、Visual
C++工程及其构建系统
(一)MSBuild
如今,Visual C++处理方案和项目都运用MSBuild执行构建,从而取代了原来的构建工具VCBUILD.exe。关于其他的Visual Studio言语和项目类型,MSBuild提供了一样的灵敏性,可扩展性和基于XML的构建支持工具。为此,Visual C++项目文件如今也运用了盛行的XML文件格式,并具有.vcxproj文件扩展名。另外,从前期版本的Visual Studio中提供的项目文件将被自动转换为新的文件格式。相关MSBuild工具的更多信息,请参见文章“MSBuild(Visual C++)”。
(二)VC++目录
如今,VC++目录配置位于两个地点。你可以运用项目属性页来配置每个项目对应的VC++目录,也可以够运用属性维护器和一个属性表来配置全局性的并且使每个配置值对应的VC++目录。
(三)工程依托性
在VC++前期版本中,您可以定义存储在同一个处理方案中的项目之间的依托性。如今在这些处理方案转换为新的项目文件格式后,相应的依托性也被转换为项目到项目的援用。这种改变将会影响使用顺序,由于处理方案依托性和项目到项目的援用是不一样的。
(四)宏与环境变量
新引入的_ITERATOR_DEBUG_LEVEL宏支持针对迭代器调用调试支持。你可以运用这个宏来替代较老的_SECURE_SCL和_HAS_ITERATOR_DEBUGGING宏。
二、Visual
(一)/analyze劝诫
绝大非少数的/analyze(企业代码剖析)劝诫如今都以前被从CRT,MFC和ATL库中移除。
(二)重启动维护器
假设您的使用系统出现不测关闭或重新启动情况的话,重启维护器支持自动保管文件偏重新启动您的使用顺序。比如,当您的使用顺序由于自动更新而关闭时您可以运用重启维护器来再次启动这个使用顺序。欲明白更多相关如何将使用顺序配置为运用启动维护器的信息,请参见《如何:添加剧启动维护支持》一文。
新引入的CTaskDialog类可用于替代规范的AfxMessageBox音讯框。CTaskDialog类可以显示和搜集比规范的音讯框更多的信息。
(四)新的ATL宏
又有新的宏被添加到ATL宏库中,以便进一步扩展原有的PROP_ENTRY_TYPE和PROP_ENTRY_TYPE_EX宏的现有功用。另外新添加的两个宏PROP_ENTRY_INTERFACE和PROP_ENTRY_INTERFACE_EX支持你添加一个有效的CLSID列表。开头一对新宏PROP_ENTRY_INTERFACE_CALLBACK和PROP_ENTRY_INTERFACE_CALLBACK_EX支持您指定一个回调函数,以确定某个CLSID能无法是有效的。
新引入的SafeInt库可以确保执行安全的算术运算,从而有效地防止了经常出现的整数溢出疑问。这个库还支持比拟不一样类型的整数。
三、集成开发环境(IDE)
(一)改进的错误智能感知支持
在Visual Studio 2010中,集成开发环境(IDE)支持更好地检测能够招致丧失智能感知支持的错误,并在这些内容下面显示以红色波浪下划线。此外,集成开发环境还支持把智能感知的错误输出到错误列表窗口中。要想观察招致疑问的相关代码,你只须要双击错误列表窗口中的错误即可。
(二)#include自动完成特征
集成开发环境还支持#include主要字的自动完成。当您键入#include时,集成开发环境将自动树立一个包括有效的头文件的下拉列表供您挑选。假设你继续输入一个文件名,集成开发环境将自动依据您的输入加以过滤。在任什么时辰候,你都可以依据这个列表来挑选你想要包括的文件。显然,这一功用可以让您高速地包括那些尚不确切知晓文件名的文件。
四、Visual
C++编译器和链接器
(一)auto主要字
如今,auto主要字有了新的用途。你可以运用默许的auto主要字来声明一个变量的类型是从此变量声明的原始化表达式中推导出的。而新的/Zc:auto编译器选项支持调用auto主要字的新意义或以前的意义。
(二)decltype操作符
decltype操作符可以前往一个指定表达式的类型。因而,你可以运用decltype操作符并结合运用auto主要字来声明一个庞杂类型或许是仅为编译器所知晓的类型。比如,你可以运用这样的组合来声明一个模板函数,而此模板函数的前往类型取决于其模板参数的类型。或许,你还可以声明一个模板函数,而此模板函数调用另一个函数,然后前往被调用函数的前往类型。
(三)Lambda表达式
Lambda函数有一个函数体,但没有函数名。Lambda函数把函数指针和函数对象两者的最好特征组合到了一同。
你可以运用一个lambda函数来作为模板函数参数以替代一个函数对象,或许结合运用auto主要字来声明一个lambda类型的变量。
(四)Rvalue援用
右值rvalue援用声明符(&&)可以声明对一个右值rvalue的援用。右值援用可以使你运用静态语义(move semantics)和完备转发(perfect
forwarding)来编写更有效的构造函数,普通函数和模板。
(五)static_assert声明
static_assert声明有助于在编译时测试软件中的断言,这不一样于其他那些在运转时执行测试的断言机制。假设断言失败,则编译失败并显示出指定的错误信息。
(六)nullptr和__nullptr主要字
Visual C++编译器准许您在本机代码或托管代码中运用nullptr主要字。nullptr主要字用于指出一个对象句柄、内部指针或本地指针类型并不指向一个对象。当您运用/clr编译器选项时,编译器将把nullptr解释为托管代码,而在不运用/clr选项时解释为本机代码。
微软特定的__nullptr主要字与nullptr主要字意思类似,但它只适用于本机代码。假设您运用/clr编译器选项编译本机C/C ++代码,那么编译器无法确定nullptr主要字是一个本地主要字照旧托管主要字。为了使编译器更清楚地了解你的意图,你可以运用nullptr主要字来指定现在操作为托管操作,而运用__nullptr主要字来指定现在操作为本地操作。
(七)/Zc:trigraphs编译器选项
默许情况下,三字符组(trigraphs)支持是被禁用的。在这种情况下,你可以运用/Z?:
trigraphs编译器选项来启用三字符组支持。
一个三字符组由两个延续的问号后面跟着一个奇特的字符组成。编译器可以运用相应的标点符号来取代这个三字符组。比如,编译器可以运用#(数字符号)字符替代三字符组??=。你还可以在C源文件中运用三字符组,由于这些文件中运用的是不会包括某些标点字符的字符集。
(八)新的基于配置的优化选项
PogoSafeMode主要字是一个新的基于配置的优化选项。你可以运用PogoSafeMode主要字来指定你想运用安全方式照旧高速方式来优化您的使用顺序。留意,安全方式是线程安全的,但它比高速方式慢一些。高速方式是默许的优化行为。
(九)新的通用言语运转时(CLR)选项/clr:nostdlib
新引入了一个通用言语运转时(CLR)选项/clr:nostdlib。假设你的系统中包括了类似库的不一样版本,那么编译器将显示错误提示。这个新的选项可以使你扫除默许的CLR库,从而使你的顺序可以运用一个特定的版本。
(十)新的pragma指令detect_mistmatch
新引入的pragma指令detect_mismatch可以支持您运用类似的称号来替换您的文件中的某个特定的标志(相关于其他的标志)。假设类似的称号拥有多个值,衔接器会发出错误提示。
(一)ATL控件向导
在ATL控件向导不再自动填充ProgID字段。假设一个ATL控件没有一个ProgID,那么其他工具能够无法运用这个控件。这样的一个工具的例子是“Insert Active
Control”对话框。相关此对话框的更多信息,请参考文章“插入ActiveX控件对话框”。
(二)MFC类向导
Visual Studio 2010中重新引入了MFC类向导。如今,您可以在处理方案的任何地点调用类向导。MFC类向导准许您添加类、音讯和变量,而不用手动修正单个的代码文件。
六、微软宏汇编器参考
新引入的YMMWord数据类型支持AVX(英特尔高级矢量扩展)指令中包括的256位的多媒体操作数。
Visual C++延伸阅读
Visual C++是微软公司开发的一个IDE(集成开发环境),换句话说,就是运用c++的一个开发平台.有些软件就是这个编出来的...另外尚有VB,VF.只是运用不一样言语...
但是,VC++是Windows平台上的C++编程环境,学习VC要明白许多Windows平台的特征并且还要掌握MFC、ATL、COM等的知识,难度比拟大。Windows下编程须要明白Windows的音讯机制以及回调(callback)函数的原理;MFC是Win32API的包装类,须要了解文档视图类的结构,窗口类的结构,音讯流向等等;COM是代码共享的二进制规范,须要掌握其基本原理等等。
已投稿到:
以上网友发言只代表其个人观点,不代表新浪网的观点或立场。}

我要回帖

更多关于 下面程序的运行结果是main 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信