【C语言】“Hello World!”的N种写法_YuJar的博客-程序员ITS203_c语言的hello world怎么写

技术标签: 转载收藏  

在初学一门编程语言的时候,写一个“Hello world!”程序是最常见的入门方法。通过写一个成功的“Hello world!”,可以实践这门语言最基本的语法特性,还可以带给自己成就感,真是一举两得。C/C++语言本身有很多特性,如果能够将这些技术分解出来变成一个个的“Hello world!”,并且将这些技术点到为止,貌似也算是一件善事。这里,列举了10个“Hello world!”程序,大家雅俗共赏一下。

1. 最经典的“Hello world!”

“Hello world!”最经典的写法当然是直接用 printf 输出“Hello world!”这几个字符了。无论用C还是 C++,写起来都非常的简洁明了。这里把最常见的几个全部列在下面。

#include <stdio.h>
#include <iostream>
int main()
{
printf("Hello world!"); // 教科书的写法
puts("Hello world!"); // 我最喜欢的
puts("Hello" " " "world!"); // 拼接字符串
std::cout << "Hello world!" << std::endl; // C++风格的教科书写法
return 0;
}

 特别需要注意的是,在C/C++里,如果两个字符串之间除空白符以外没有任何东西,编译器会自动认为这两个字符串是连在一起的字符串。这样,如果一个字符串过长,可以用这种方法换行来写,既不浪费性能,又美观。

2. 用宏写的“Hello world!”

在C/C++里,宏是一个神奇的东西。特别是在C语言中,宏可以帮我们做一些“又脏又累”的活,包括拼接代码片断、隐藏繁琐的实现细节等等。其中特别有趣的是“#”的用法,它可以“提取”参数的名字,把它变成字符串。

#include <stdio.h>
#define Say(sth) puts(#sth)
int main()
{
return Say(Hello world!);
}

 请注意,这个Hello world可是完全没有出现引号哦!

3. 断章取义的“Hello world!”


字符串是一种常量这当然毫无疑问,但是它的类型是什么,这就需要考虑一下了。使用C++的typeid就可以这个问题的答案,而且只要是符合C或C++标准的编译器就应该是一样的结果。比如字符串“Hello world!”,它的类型就是 char const [13]。
知道了这个,就可以写出以下的“Hello world!”:

#include <stdio.h>
int main()
{
return puts(&"Do not say: Hello world!"[12]);
}

 4. 退出时运行的“Hello world!”

大家都知道 main 函数退出意味着程序结束,可是这并不完全正确,我们完全可以在 main 函数退出以后做很多事呢——比如说,输出“Hello world!”。这个功能依赖于C标准库中提供的函数 atexit(),调用这个函数并注册自己的回调函数就行。需要注意,这个函数可以调用多次,最后注册的函数最先执行。

#include <stdio.h>
#include <stdlib.h>
void say()
{
printf("world!");
}
void sth()
{
printf("Hello ");
}
int main()
{
return atexit(say), atexit(sth);
}

 5. 读取自己的“Hello world!”

C/C++的编译器提供了一些有用的内置宏,最常用的就是 __FILE__ 和 __LINE__ 了。其中,__FILE__ 代表当前的源文件的文件名,嗯,对了,如果我们让这个程序读取自己的源文件,不就可以做一个很有意思的“Hello world!”了么?

// Hello world!
#include <iostream>
#include <fstream>
#include <string>
int main()
{
std::ifstream ifs(__FILE__);
std::string say, some, word;
ifs >> say >> some >> word;
std::cout << some << " " << word;
return 0;
}

6. 话分两头的“Hello world!”

有了C++的类,我们就可以光明正大的在 main 函数执行之前和之后做感兴趣的事情了。我们可以声明一个全局的类的实例,这样,在 main 函数执行之前会调用这个类的构造函数,结束之后则会调用析构函数。

#include <iostream>
// 本代码转自 C++Builder研究
class say
{
public:
say()
{
std::cout << "Hell";
}
~say()
{
std::cout << "world!";
}
}hello;
int main()
{
std::cout << "o ";
return 0;
}

7. 传入模板的“Hello world!”

C++的模板功能极为强大,可以说是C++里面最艰深、最经典、最时尚的部分。一个“Hello world!”当然无法使用很多很高级的模板技巧,我也不想只使用模板特化这样无阻挂齿的小技巧,嗯,那就来演示一个比较罕见的用法吧。

#include <iostream>
template <char * words>
class say
{
public:
void operator () ()
{
std::cout << words;
}
};
extern char hello[] = "Hello world!";
int main()
{
return say<hello>()(), 0;
}

 请注意,这个 extern 是十分必要的,只有加上了 extern,这个指针才是一个编译器间可以确定的值,也才可以参与模板运算。还有,hello 必须为数组类型,而不能为 char*,这个道理和加 extern 是一样的。
此外,这里还演示了 functor 的用法,嗯,关于它的优点就不在这里多说了,反正是与原生指针相比有很多好处就是了。

8. 调用私有函数的“Hello world!”

我们知道,C++类的私有函数是不能被外界访问的,比如说 main 函数里面,它绝对不能访问类的私有函数,除非把它设为类的友元函数。不过我们还是可以用一些比较奇怪的方法访问类的私有函数——当然,这个私有函数必须满足一个条件:它是虚函数。
这里就涉及到一个问题,指向虚函数的虚表放在哪里?对于 VS.Net 2003 而言,虚表是类的第一个成员,虚函数指针按照函数声明的顺序放在虚表里面。当然,这个说法并不严谨,更细节的东西还是去看看那本“成人高钙奶粉”吧,它会给出最权威的解答。
这里是一个很有意思的例子:

#include <iostream>
#include <cstddef>
class secret
{
private:
virtual void say()
{
std::cout << "Hello world!";
}
};
int main()
{
secret word;
(reinterpret_cast<void (*)()>(**(intptr_t**)(&word)))();
return 0;
}

9. 最暴力的“Hello world!”

 最暴力的调用函数的方法是:直接修改函数的返回地址,让这个地址指向我们想要调用的函数。这也就是缓冲区溢出漏洞的应用方法了,不过里面还涉及到很多问题,在这里就不一一列举,想要了解的话,还是去 Google 吧。这里只演示一个可以在 VS.Net 2003 下可以用的“Hello world!”。

#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
void say()
{
puts("Hello world!");
exit(0);
}
int main()
{
volatile intptr_t a = 0;
volatile intptr_t * p = &a;
*(p + 2) = (intptr_t)say;
*(p + 3) = (intptr_t)say;
return 0;
}

10. 外星人说的“Hello world!”

好了,这个“Hello world!”是最匪夷所思的一个了!不过它并没有涉及任何复杂的C/C++语言特性,只是看起来有点酷。你能看懂外星人在说什么不?

#include <stdio.h>
void alien_say(char * p)
{
while (putchar(*(p += *(p + 1) - *p)));
}
int main()
{
return alien_say("BETHO! Altec oh liryom(a loadjudas!) dowd."), 0;
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/u010345869/article/details/23663593

智能推荐

tensorflow安装步骤(CPU版本,Anaconda环境下,Windows10)_萝北村的枫子的博客-程序员ITS203_tensorflowcpu安装教程

本文主要讲述了在Anaconda环境下,CPU版本tensorflow2.3.0的安装步骤,Windows10系统中Anaconda的安装步骤可以阅读此篇博客:用Anaconda安装TensorFlow(Windows10)本文分为两大部分:一、TensorFlow2.3.0安装步骤二、对TensorFlow2.3.0进行验证一、TensorFlow2.3.0安装步骤1.打开Anaconda Prompt2.输入下面命令,利用Anaconda创建一个python3.7的环境,环境名称为tensor

numpy数组切片操作_whitesilence的博客-程序员ITS203

numpy 数组的切片操作 关于-1的解析再来看个多维数组的情况A=np.array(range(24))A=np.reshape(A,[4,3,2])输出:Aarray([[[ 0, 1], [ 2, 3], [ 4, 5]], [[ 6, 7], [ 8, 9], [10, 11]], [[1

php socket 类,php socket通信演示以及socket操作类_UEGamer的博客-程序员ITS203

准备做Java的课程设计,一个通讯录。采用C/S架构。客户端用java FX和Java,服务器端用php,采用socket通信。下面来讲一讲php的socket通信:讲之前,得先讲一下TCP/IP,UDP。随着互联网应用的日益广泛,相信很多人或多或少都听说过这些协议,那么到底它们是什么呢?1、什么是TCP/IP、UDP?TCP/IP(Transmission Control Protocol/In...

WPF DX10 DX11 interoperation_lhy_ps6的博客-程序员ITS203

WPF host DX9 的surface通过d3dimage,wpf unleashed 这本书里有提到。但是DX10,DX11之类的就比较麻烦,因为Dx10之后的surface与dx9的不一样。目前所知有如下解决方案:1.完全将dx11做一个c# wrapper。请搜索 Windows API Code Pack 1.12.参考kinect的一个wpf d3d demo。装上k

Semantic UI入门示例_xiaobudingCC的博客-程序员ITS203

1.下载Semantic UI包引入相关文件遇到各种各样的问题,比如icon找不到、无动效等问题,所以通过链接的方式引入文件。2.在页面引入文件(按照顺序)引入文件内容如下:            3.接下来就可以使用Semantic UI的样式了。

CTF 每日一题 Day42 [BJDCTF2020]这是base?_ChaoYue_miku的博客-程序员ITS203

题目名称:[BJDCTF2020]这是base??题目类型:Crypto题目来源:BUUCTF题目描述:听说这题是rsa的续集 注意:得到的 flag 请包上 flag{} 提交

随便推点

Android共享文件的几种方式_14梧桐雨的博客-程序员ITS203

一、使用SQLite实现对数据的操作:第一步:建立一个要操作的表对应的javabean第二步:创建一个类,继承SQLiteOpenHelper(完成数据库和表的创建,以及软件升级时,对数据库、表结构进行更新)第三步:创建一个类,实现对数据的CRUD(Create/Read/Update/Delete)操作(将SQLiteOpenHelper的实例传入其中,从而可以对数据库进

Oracle to_date(...)函数相关_流浪的侠客的博客-程序员ITS203

在Oracle数据库中,Oracle to_date()函数是我们经常使用的函数,下面就为您详细介绍Oracle to_date()函数的用法,希望可以对您有所启迪。to_date()与24小时制表示法及mm分钟的显示:一、在使用Oracle的to_date函数来做日期转换时,很多Java程序员也许会直接的采用“yyyy-MM-dd HH:mm:ss”的格式作为格式进行转换,但是在

使用plsql创建的用户,以普通身份无法登录进去,提示ORA-01017: 用户名/口令无效; 登录被拒绝_好喵的博客-程序员ITS203_plsql登录被拒绝

使用plsql创建的用户,以普通身份无法登录进去,提示ORA-01017: 用户名/口令无效; 登录被拒绝,一直以为是自己的Oracle出现了问题,然后重新卸载再安装后,使用plsql连接后创建新的用户仍然出现该问题,在网上查的结果也大部分是给创建的用户修改密码等等,但是修改后仍然不起作用最后花费了好久的时间是因为tnsnames.ora文件配置的原因,该文件是安装Oracle的时候的自带的配置文

CMake和Make之间的区别_android_ruben的博客-程序员ITS203_cmake和makefile区别

本文翻译的是一篇英文文档,主要讲述的是CMake和Make之间的区别。下文中首先列出文章的中文翻译,然后紧接着的是英文原文。 下面是中文翻译部分:  编程人员已经使用CMake和Make很长一段时间了。当你加入一家大公司或者开始在一个具有大量代码的工程上开展工作时,你需要注意所有的构建。你需要看到处跳转的“CMakeLists.txt”文件。你应该会在终端使用”cmake”和”make”。很多人都

IntelliJ IDEA中Tomcat服务器中无Update classes and resources的解决方法_joey小天使的博客-程序员ITS203

1.问题描述第一次使用ssm框架发现on “Update” action中没有Update classes and resources选项了,这就是说如果更新静态资源都要重启服务器,在开发过程中十分麻烦,查了一晚上也没有找到bug2.解决办法原来是artifact的问题:Artifacts,它的作用是整合编译后的 java 文件,资源文件等,有不同的整合方式,比如war、jar、war exploded 等,对于 Module 而言,有了 Artifact 就可以部署到 web 容器中了。其中 w