你有没有遇到叫二狗子的那个哥们?

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

原文 调侃C中的define,CSDN同步发布。

转载请注明出处,谢谢!


二狗子

二狗子这个名字,在大街小巷,在电视剧中几乎都能听到。我也不知道老一辈的父母为什么这么喜欢给自己的孩子取这样的名字,唯一能让我信服的理由是:顺口!大叔大伯们之所以叫这个名字还有一个理由,之前孩子多,希望孩子像小狗儿一样好喂养。

正好我们村有个孩子也叫二狗子,大名叫张力万,无论是叫二狗子还是叫张力万,都指的是同一个人。我们大多数情况下还是叫他二狗子,他也习惯了倒也觉得亲切,叫张力万一般都是在正式场合。

有些企业文化中规定:“不允许在公司直接喊同事的名字,每个人必须有个英文名”。比如二狗子入职到这样的企业,大家不允许喊他二狗子或者张力万,于是二狗子又有了一个英文名:“Jack”,你看 “Jack” 这个名字既符合企业文化又听起来高大尚。

无论是 “二狗子“ 还是 “Jack“ 都是张力万的别名。

在 C 语言中,关键字 definetypedef 就可以用来取别名,但是二者又有不同点,今天主要分享一下 define 的用法。

下面是使用 define 来模拟别名,示例如下:

#define Zhangliwan1 "二狗子"
#define Zhangliwan2 "Jack"

#define Zhangliwan "张力万"

int main(int argc, const char *argv[])
{
    printf("我们村的%s可以叫他%s也可以叫他%s\n", Zhangliwan, Zhangliwan1, Zhangliwan2);
    
    return 0;
}

输出结果:

我们村的张力万可以叫他二狗子也可以叫他Jack

虚构一下

丹尼斯·里奇 一个伟大而低调的牛人,是Unix之父、C语言之父。

丹尼斯·里奇还将Unix的设计原则定为 KISS 原则 即 Keep it simple stupid,保持简单和直接,所以Unix一直都是经典中的经典。这也说明丹尼斯·里奇不仅是一个优秀的工程师,还是一个优秀的产品经理。

我在想,当初丹尼斯·里奇和肯·汤普逊在实验室里没事也会讨论C语言的事情。

丹尼斯·里奇:“老兄,你看我们现在的语言是不是过于复杂了?”

肯·汤普逊:“的确有点复杂,我有个大胆的想法,不知当讲不当讲?”

丹尼斯·里奇:“你还跟我墨迹啥,有话直接说呗,呵呵!”

肯·汤普逊:“嗯,我们可以开发一门新的语言,他要足够的简单、高效。”

丹尼斯·里奇:“想法是挺好的,那就开干吧!”

于是C语言诞生了。

肯·汤普逊:“你有没有觉得我们在定义常量的时候不太方便?”

丹尼斯·里奇:“是呀,这样你看行不行,弄个预处理器可以让我们任意定义常量,暂时称他为 ‘宏’ 吧!”

肯·汤普逊:“我觉得完全没有问题,来,徒手写一个。”

丹尼斯·里奇:“哈哈,给力!”

于是 define 就有了。

以上纯属个人猜想,并不是冒犯两位大师,本故事纯属虚构,如有雷同,纯属巧合。Unix和C语言的大道至简,对后代科学的发展奠定了不可磨灭的贡献和影响。

基本用法

关键字 define 是 C 语言中的预处理命令,它用于宏定义,在大多数定义下可以提高代码的可读性,为编程提供方便。

在 C 语言中预处理命令以 “#” 号开头,如 #include#ifdef#endif 和宏定义命令 #define 等。

关键字 define 的用法如下:

#define 新类型名 原类型名
#define INTEGER int
INTEGER a = 100;

#define PI 3.1415927

#define UserName "user_name"

#define MAX(x, y)	 (x)>(y)?(x):(y);

在 C 语言中,关键字 define 的定义的常量都会在预处理阶段将用到的别名直接被原样替换掉。例如在编写源程序时,所有用到 3.1415927 的地方都可用 PI 代替,而编译时,将先由预处理程序进行宏代换即用 3.1415927 去置换所有的宏名 PI,然后再进行编译。

关键字 define 还可以结合 “#”、“##”、“#@” 使用。

  • 符号 “#”,表示将其字符串化。
  • 符号 “##”,表示连接变量。
  • 符号 “#@”,表示将其字符化。
#define M(x) x##x
#define L(x) #x

int main(int argc, const char *argv[])
{
	// M(1): 11, L(1): "1"
	printf("M(1): %i, L(1): %s\n", M(1), L(1));
}

我使用 “#@” 定义,无论是GCC编译器还是Clang编译器都无法通过编译,错误信息:“ ‘#’ is not followed by a macro parameter ”,但是在 Visual Studio 中编译就没有问题。示例如下:

#define K(x) #@x

关键字 define 给我们写代码带来了一定的便利,但是如果过多的乱用它也会代码不小的麻烦,比如下面的例子:

#define square(x) x*x

int main()
{
	int i;
	i = 64/square(4);
	printf("i = %d\n", i);
	
	return 0;
}

定义宏 square(x) 本来是求某个数的平方,按理说 64/16 结果应该是 4,但是运行程序你会发现结果是 64.

我们把上面的例子展开,因为 define 是直接原样替换,如下:

i = 64/4*4;
i = 16*4;
i = 64;

修改一下程序中 define 的定义,结果就对了。

#define square(x) (x*x)

int main()
{
	int i;
	i = 64/square(4);
	// 4
	printf("i = %d\n", i);
	
	return 0;
}

其实最安全的做法是这样定义,如下:

#define square(x) ({    \
typeof(x) y = (x);  \
y*y;                \
})

作用域

可以在C文件的开头,也可以在方法体里面,还可以在方法的声明前都可以使用 define 关键字。

定义在文件开头:

#define NAME "name"

int main()
{
	printf("Define NAME: %s\n", NAME);
    return 0;
}

定义在方法中:

void play()
{
	#define NAME "name"
	printf("Define NAME: %s\n", NAME);
}

这里要注意,定义在方法中,并不是指该宏定义 NAME 只能用在该方法里面,其他地方照样可以使用。

void play()
{
	#define NAME "name"
	printf("Define NAME: %s\n", NAME);
}

/* 注意:该方法一定是在define定义之后才能使用NAME */
void eat()
{
	printf("Define NAME: %s\n", NAME);
}

条件编译

在C语言中或者在类C语言中如Objective-C和C++中,我们会经常用到条件编译语句,如下:

#ifdef NAME

#else

#endif

大家在做一些跨平台开发工作的时候,也会用到条件编译语句。

#ifdef ANDROID
#define PLAYFORM 1
#else
#define PLAYFORM 2
#endif

还有就是类似防止重复包含(重复定义)头文件,也会用到条件编译,如下:

#ifndef __Header_Person_H__
#define __Header_Person_H__
#endif

下面是来自Linux Kernel里面的代码片段:

#if defined(CONFIG_ALPHA_GENERIC)
#define GAMMA_BIAS		alpha_mv.sys.t2.gamma_bias
#elif defined(CONFIG_ALPHA_GAMMA)
#define GAMMA_BIAS		_GAMMA_BIAS
#else
#define GAMMA_BIAS		0
#endif

既然我们可以定义宏,那么是否可以取消宏定义呢?答案是当然可以。

void play()
{
	#define NAME "name"
	printf("Define NAME: %s\n", NAME);
}

#ifdef NAME
// 取消宏定义
#undef NAME
#endif

void eat()
{
	// Compile errror: Use of undeclared identifier 'NAME'
	printf("Define NAME: %s\n", NAME);
}

这份 GNU Macors 在线文档介绍了很多关于宏定义的知识,可以点击前往学习。


时间可以改变一切,但你得做点什么!

展开阅读全文

那个叫老家的小镇(原创)

07-08

那个叫老家的小镇rn无意中搜索到这篇文章:那个叫老家的小镇.rnrnhttp://www.iambackpacker.com/ShowArticle.asp?ArticleID=107rnrn海草文章里那个叫老家的小镇也就是我的老家(可能也是我将来的家):四川省开江县任市镇.rnrn rnrn看完文章后,我的心中弥漫着一种说不清道不明的情绪,或许这就是远在他乡游子对于故乡亲人深深的想念.(写下下面这些文字,以表达我深深的思念)rnrn rnrn那个叫老家的小镇,是生我养我的地方.rnrn rnrn小镇位于四川无数丘陵中的一个角落,四面环绕的小山包中间难得一块不是很平的平地,小镇就坐落在这块平地上.就在我家们前,一条弯弯的小河傍着小镇,流向小镇另一边更大的一条河.这两条河给我和我少年时候的朋友们带来了太多的快乐.我爸是小镇上出名的捉鱼\捉黄鳝的高手,小镇以外其他地方的很多人都认识他.每每到了夏天,我爸就带领我的几个年龄比较大些的堂哥下河捕鱼,小的时候拉不动网,就帮大人们提些衣服鞋子之类的东西,屁颠屁颠的跟着他们沿河跑,时不时下水在浅水的地方摸小鲫鱼;再大些的时候就拉网往深水的地方去,扎猛子下水捉河底乱石中被网住的的鱼.亦或者在水枯的季节到离小镇不远的山上去采熟透的马桑的籽,也就是马桑葚里面的籽(马桑葚也是我们的美味啊,只是不能多吃),然后将马桑籽放菜油炒香,跑到河的上游撒在河中,然后从那里到下游很远的地方,就会有吃了马桑葚的鱼浮起来,满河都是象喝醉了的小鲫鱼浮在水面,沿河象我们这么大的小孩子都拿着网子去舀鱼.rnrn可惜的是随着我们的长大,由于沿岸水土的流失(伐木),小河一天天变窄变小了,一如贾平凹笔下的那条州河.到现在由于水浅,加上电打药炸,河中鱼儿更是稀少了.rnrn rnrn那个叫老家的小镇,见证了历史的变迁.rnrn rnrn在我的记忆中最老的建筑:我家的老屋,已经在前几年拆掉了.rnrn在我的祖父那一代以前,小镇上的人们都以族为单位居住.在老家,王姓是一大姓,老屋是有名的王家面房,曾祖父靠做擀面养活了一大家子人.而我的祖父,在我爸还很小的时候,因为修房子抬屋脊上梁,而在房子还没完工就痨病过世了.我的也已经过世的奶奶,这个坚强而又受人尊敬的小脚女人,挣扎着一手带大了五个儿子,两个女儿.rnrn在那些穷困的日子里,我的爸爸有幸去当兵,然后退伍后靠退伍的一点钱,修了两间土砖房,在那时可是不错的建筑.童年的记忆中,除了小镇上的供销社和二中和任小是青砖瓦房外,乡民们住的都是木板加蔑壁的草屋,在我稍微懂事的时候,改革开放之风开始吹拂神州大地,老家的建筑发生了翻天覆地的变化,从一层青砖碧瓦到两三层小洋楼,所有的这一切替换了过去的毛草棚.rnrn两年前,达万铁路建成通车,给小镇带来新的机会.今年和去年春节在家的日子里,我都和我的老婆,父母(去年还抱上了我的儿子),在初一的早上从家门口的铁路出发,沿铁路走到镇的另一端的火车站,铁路上很多象我们这样一家子.估计其中很多在外长期工作的人.在这喜气的日子里合家感受新生活的美好,感受小镇的变迁.rnrn年年回家,都会发现小镇发生了新的变化.或许唯一不变的,是小镇达洲街上列为历史保护文物的古旧的牌坊,她静静的,静静的感受着小镇的变迁…rnrn rnrn那个叫老家的小镇,有我永远的挂牵.rnrn rnrn或许今生最大的遗憾是没有上过大学,我想或许正因为这个原因,我的心一直没有走出小镇.rnrn二十岁之前我去过最远的地方就是开江县城,还是因为高考而去的.二十岁后我离开家乡,去了海南,开始了流浪的生活.飘泊的在外的日子是没有家的日子,有的只是’一张张的票根’.rnrn十年的闯荡,到今天依然尴尬.城市不是我的城市,我依然属城市边缘一族,梦想着有遭一日能在这里安家落业,或者到重庆或成都定居.rnrn努力想挣脱老家的同时,我深深的挂牵着小镇,那里有我的父母,有我的老婆和孩子,有我眼看着我长大的叔伯,有我儿时的也是现在的朋友们!rnrn rnrn那个叫老家的小镇,午夜梦回时,我又见到了你…rn 论坛

有没有斗地主叫分的简单算法

03-22

我写的感觉太复杂了 哪位高手有简单点的算法 指点指点rn我自己都快看不懂了rnrnrn斗地主的叫分算法 一方是玩家叫分 另外两方是电脑随机叫分 叫分方法跟QQ斗地主一样rn 0代表不叫 1-3代表分数 随机选取最先叫分的玩家 不能叫小于前面玩家所叫分数的最大值rn rnrnrnrn[code=C/C++]rn#include "stdafx.h"rn#include rn#include rn#include rnrnint compare(int x,int y,int z) /*比较三个数的大小*/rnrn if(x>y)rn rn if(x>z)rn rn return 0; //返回0 代表玩家x叫的数最大rn rn elsern rn return 2; //返回2 代表玩家z叫的数最大rn rn rn elsern rn if(y>z)rn rn return 1; //返回1 代表玩家y叫的数最大rn rn elsern rn return 2; //返回2 代表玩家z叫的数最大rn rn rnrnrnint callcent1(int *x) /*找地主之1 电脑玩家最先叫分*/rnrn *x=rand()%4; //随机选取(0)不叫,或者大于玩家x的数值 4-x剩余可选数的个数rn if(*x==3) //如果x等于3 x玩家是地主rn rn return 0; //返回0 代表x玩家是地主rn rn elsern rn return -1;rn rnrnint callcent2(int x,int *y) /*找地主之2 电脑玩家随机叫分*/rnrn *y=rand()%(4-x); //随机选取(0)不叫,或者大于玩家x的数值 4-x剩余可选数的个数rn if(*y!=0) //如果玩家x选择了不是0(不叫)的分数rn rn *y=(*y)+x; //剩余可选个数的随机数加上玩家x所选的分数 不会大于3并且不小于xrn rn if(*y==3) //如果y等于3 y玩家是地主rn rn return 1; //返回1 代表y玩家是地主rn rn elsern rn return -1;rn rnrnrnint callcent3(int x,int y) /*找地主之3 找最大叫分值*/rnrn int maxdata;rn if(x>y) //比较x与y的大小 最大数的赋给data;rn rn maxdata=x;rn rn else //比较x与y的大小 最大数的赋给data;rn rn maxdata=y;rn rn return maxdata;rnrnrnint callcent4(int maxdata,int *z) /*找地主之4 电脑玩家随机叫分*/rnrn *z=rand()%(4-maxdata); //随机选取(0)不叫,或者大于其它玩家最大的叫分值 4-x剩余可选数的个数rn if(*z!=0) //如果玩家x选择了不是0(不叫)的分数rn rn *z=(*z)+maxdata; //剩余可选个数的随机数加上玩家z所选的分数 不会大于3并且不小于xrn rn if(*z==3) //如果z等于3 z玩家是地主rn rn return 2; //返回2 代表z玩家是地主rn rn elsern rn return -1;rn rnrnrnint callcent5(int x,int y,int z) /*找地主之5 判断最终叫分情况*/rnrn if(x==0&&y==0&&z==0) //如果玩家x,y,z都选择0(不叫)rn rn printf("重新发牌\n");rn printf("x==%d y==%d z==%d ",x,y,z);rn return -1;rn rn elsern rn return compare(x,y,z); //选择最大数的玩家做为地主rn rnrnrnrnint callcent6(int *x,int maxdata) /*找地主之6 玩家x叫分*/rnrn while(*x<0||*x>3-maxdata) //控制数字在[0,3-data]之间rn rn printf("请输入大于0,并且小于3-maxdata的分数:\n");rn scanf("%d",x); //超出[0,3-data] 重新输入rn if(*x!=maxdata) //这里是为了方便习惯性输入3和0rn rn if(*x!=0) rn rn *x=*x-maxdata; //将其减小到出循环的情况rn rn rn rn if(*x!=0) //如果玩家x选择了不是0(不叫)的分数rn rn *x=*x+maxdata; //剩余可选个数的随机数加上其它玩家所选的最大分数 不会大于3并且不小于最大数rn rn if(*x==3) //如果x等于3 x玩家是地主rn rn return 0; //返回0 代表x玩家是地主rn rn elsern rn return -1;rn rnrnrnint callcent7(int j,int *k) /*输出哪个玩家是地主*/rnrn *k=(j+(*k))%3; //0是玩家x,1是电脑玩家y,2是电脑玩家zrn switch(*k)rn rn case 0:rn printf("最终地主是玩家x:\n");rn return 0;rn case 1:rn printf("最终地主是玩家y:\n");rn return 1;rn case 2:rn printf("最终地主是玩家z:\n");rn return 2;rn rn return -1;rnrnrnvoid output_x(int x) /*输出x*/rnrn printf("x==%d",x);rn printf("\n");rnrnvoid output_y(int y) /*输出y*/rnrn printf("y==%d",y);rn printf("\n");rnrnvoid output_z(int z) /*输出z*/rnrn printf("z==%d",z);rn printf("\n");rnrnrnrnint laird(int *k) /*找地主过程*/rnrn int j,x=-1,y;rn int maxdata,z=-1;rn printf("0代表不叫|1代表1分|2代表2分|3代表3分:\n");rn *k=rand()%3;;rn printf("\n");rn if(*k==0) //随机选到 玩家x 最先叫分的情况rn rn printf("最先叫分的是玩家x;\n");rn j=callcent6(&x,0); //玩家x最先叫分rn output_x(x);rn if(j==0) //0代表地主是玩家xrn rn return j;rn rn j=callcent2(x,&y); //电脑玩家y叫分rn output_y(y);rn if(j==1) //1代表地主是电脑玩家yrn rn return j;rn rn maxdata=callcent3(x,y); //前两个玩家叫分的最大值rn j=callcent4(maxdata,&z); //最后一个电脑玩家z的叫分值rn output_z(z);rn if(j==2) //2代表地主电脑玩家zrn rn return j;rn rn j=callcent5(x,y,z); //比较三个玩家的叫分情况rn return j;rn rn if(*k==1) //随机选到 电脑玩家y 最先叫分的情况rn rn printf("最先叫分的是玩家y;\n");rn j=callcent1(&x); //电脑玩家y最先随机叫分rn output_y(x);rn if(j==0)rn rn return j; //0代表地主是电脑玩家yrn rn j=callcent2(x,&y); //电脑玩家z随机叫分rn output_z(y);rn if(j==1)rn rn return j; //1代表地主是电脑玩家zrn rn maxdata=callcent3(x,y); //前两个玩家叫分的最大值rn j=callcent6(&z,maxdata); //最后一个玩家x的叫分值rn output_x(z);rn if(j==0)rn rn j=2; //2代表地主是玩家xrn return j;rn rn j=callcent5(x,y,z); //比较三个玩家的叫分情况rn return j;rn rn else //随机选到 电脑玩家z 最先叫分的情况rn rn printf("最先叫分的是玩家z;\n");rn j=callcent1(&x); //电脑玩家y最先随机叫分rn output_z(x);rn if(j==0)rn rn return j; //0代表地主是电脑玩家zrn rn j=callcent6(&y,x); //电脑玩家x叫分rn output_x(y);rn if(j==0)rn rn j=1; //1代表地主是电脑玩家xrn return j;rn rn maxdata=callcent3(x,y); //前两个玩家叫分的最大值rn j=callcent2(maxdata,&z); //最后一个玩家y的叫分值rn output_y(z);rn if(j==1)rn rn j=2; //2代表地主是电脑玩家yrn return j;rn rn j=callcent5(x,y,z); //比较三个玩家的叫分情况 rn return j;rn rnrnrnint main()rnrn srand( (unsigned) time(NULL) ); //随机分配种子rn int j;rn int k;rn j=laird(&k); //找地主过程rn callcent7(j,&k); //判断地主归属rnrn[/code] 论坛

那个哥们帮忙看看问题出在哪?

06-10

客户端文件调用组件的时候出现问题 提示程序出现错误中止 我问同学有的说是数据库调用问题 有的说是定义的IAccount *IAccount; 没有初始化 希望懂MFC和ATL组件编程的朋友帮忙看看 这个是自动取款机的设计代码 小弟在此表示感谢、代码入下 (有想帮忙的朋友加我好友,我把完整代码传给你,您帮我看看 我的 QQ :6169580)rn客户端代码:rnvoid CDlgLogin::OnOK() rn UpdateData(TRUE);rnrn HRESULT hr;rn IAccount *IAccount; //指向接口的指针rnrn// UpdateData(TRUE);rnrn BSTR AccountID = A2BSTR(m_sAccount);rn BSTR Pswd = A2BSTR(m_sPswd);rnrn //hr = CoCreateInstance(CLSID_Account,NULL,CLSCTX_SERVER,IID_IAccount,(void**)&IAccount ); rn COSERVERINFO srvinfo=0,L"192.168.0.92",NULL,0;rn MULTI_QI MultiQI = &IID_IUnknown,NULL,NOERROR;rn hr=CoCreateInstanceEx(CLSID_Account, NULL, CLSCTX_REMOTE_SERVER,rn &srvinfo,1, &MultiQI); rn if(hr!=0)rn AfxMessageBox("COM组件创建失败!");rn elsern rn BOOL IsAccountValid = FALSE;rn rn hr = IAccount->Login(AccountID,Pswd,&IsAccountValid); // call methodrn g_IsAccountValid = IsAccountValid;rn g_AccountID = m_sAccount;rn hr = IAccount->Release(); //释放接口rn rnrn CDialog::OnOK();rn调试到rn hr = IAccount->Login(AccountID,Pswd,&IsAccountValid); // call methodrn g_IsAccountValid = IsAccountValid;rn g_AccountID = m_sAccount;rn hr = IAccount->Release(); //释放接口rn就不能运行了 rnrn组件部分代码 连接数据库部分rnBOOL CAccount::ConnectDBSource(/*BSTR AccountID,BSTR Pswd*/)rnrn //-------------连接数据源---------------rn try rn rn CoInitialize(NULL); // 初始化COM.rn m_pConnection.CreateInstance(__uuidof(Connection)); //实例化_ConnectionPtr对象,并调用Open方法rn m_pConnection->Open("DSN=BankAccount;", _bstr_t(""), _bstr_t(""),adModeUnknown ); rn if (NULL== m_pConnection) rn rn MessageBox(NULL,_T("连接数据源出错!"),_T("ERROR"),MB_OK);rn return FALSE;rn rn elsern return TRUE;rn rn登陆部分:STDMETHODIMP CAccount::Login(BSTR AccountID, BSTR Pswd, BOOL *pIsValid)rnif(ConnectDBSource())rn rn //---创建命令----------------------------------------rn pCommand.CreateInstance (__uuidof (Command));rn pCommand->ActiveConnection = m_pConnection; rnrn _bstr_t strSQL ="Select * From Account Where AccountID Like '";rn strSQL+=AccountID;rn strSQL+="' And Password Like'";rn strSQL+=Pswd;rn strSQL+="'"; rn pCommand->CommandText = strSQL ; //拼写查询字串rnrn pRecordset.CreateInstance (__uuidof (Recordset));rn pRecordset->CursorLocation = adUseClient;rn pRecordset->Open((IDispatch *) pCommand, vtMissing, adOpenStatic, adLockOptimistic, adCmdUnknown);rn //----------------------rn if(pRecordset->adoEOF) //若未找到则返回FALSErn *pIsValid = FALSE;rn else //若找到则返回TRUErn *pIsValid = TRUE;rn CoUninitialize(); //中止COMrn rn return S_OK;rnrn 论坛

没有更多推荐了,返回首页