【C语言】宏定义(写一个宏可以将一个数字二进制的奇数位和偶数位交换)

 1.写一个宏可以将一个数字的奇数位和偶数位交换。 

#define _CRT_SECURE_NO_WARNINGS 1  

#include <stdio.h>
#define FSWAP(N) (((N&0X55555555)<<1)|((N&0xaaaaaaaa)>>1))

int main()
{
	int n = 0;
	printf("请输入一个数字\n");  
	scanf("%d",&n);
        printf("%d",FSWAP(n));	
	return 0;
 } 

 看到这个题目的时候我想如何才能将两个数字中的奇数位和偶数位进行交换,最初的时候我想的是用一个数组将数字中的每一位存储起来,然后进行输出,之后我一直在想怎么将这个功能实现到宏定义里边,后来想了很多都发现这不可能,所以我百加思索才发现,这里的奇数偶数进行交换是将他的二进制数进行的奇数偶数位进行交换,既然是对二进制进行交换了那大家自然也就想到了按位与按位或这种二进制操作,很多人纳闷0x55555555这个是个什么,这个实际上就是十六进制的10101010101010101010101010101010,就是它,所以开始先将n和它按位与,求出来n的所有偶数位置的数字,然后将求得的数左移一位,现在的数字就是将n的奇数位的所有内容放到了偶数位置,这时候只要求出来n的偶数为然后放到奇数位置就可以了,所以先移动n向右移虽然这时候n的32位少了一个,但是少的那个是32位的奇数位,所以并不影响, 然后将两个求得的数字进行或运算,就能将这个数字的32位二进制的奇数位和偶数位进行交换

2.使用宏实现两个数中求较大值。

#define _CRT_SECURE_NO_WARNINGS 1  
#include<stdio.h>  
#define MAX(a,b) a>b?a:b  
  
int main()  
{  
    int x = 0;  
    int y = 0;  
    printf("请输入两个数值\n");  
    scanf("%d %d", &x, &y);  
    printf("两个数字中较大的是%d", MAX(x, y));  
    return 0; 
}  
拓展小常识:
       

 使用宏,不仅使代码看起来整洁,而且用好了还能极大的减轻编码的工作量,但是如果使用不当的话,出了问题查找起来就就非常的难了 .

宏使用中的常见的基础问题

1. 防止一个头文件被重复包含
#ifndef  __GAME_H__
#define __GAME_H__
//头文件内容
#endif //__GAME_H__

2.使用一些宏跟踪调试
ANSI标准说明了五个预定义的宏名。它们是:
__LINE__ (两个下划线),对应%d
__FILE__ 对应%s
__DATE__ 对应%s
__TIME__ 对应%s
__STDC__ 

如果编译不是标准的,则可能仅支持以上宏名中的几个,或根本不支持。记住编译程序也许还提供其它预定义的宏名。
__LINE__宏指令表示当前指令所在的行,是个整型数
__FILE__宏指令表示当前指令所在文件,包含完整路径
__DATE__宏指令含有形式为月/日/年的串,表示源文件被翻译到代码时的日期。
__TIME__宏指令包含源代码翻译到目标代码的时间。串形式为时:分:秒。
如果实现是标准的,则宏__STDC__含有十进制常量1。如果它含有任何其它数,则实现是非标准的  //  VS 不是标准  gcc 标准。

可以定义宏,例如:
当定义了_DEBUG,输出数据信息和所在文件所在行
#ifdef _DEBUG
#define DEBUGMSG(msg,date) printf(msg);printf("%d%d%s",date,_LINE_,_FILE_)
#else
#define DEBUGMSG(msg,date)
#endif

3.宏中"#"和"##"的用法
在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。
而##被称为连接符(concatenator),用来将两个Token连接为一个Token.注意这里连接的对象是Token就行,而不一定是宏的变量。
我们使用#把宏参数变为一个字符串,#@把参数变为字符,用##把两个宏参数贴合在一起。

    #define  fun(dst, str)  strcpy(dst, #str)
//fun(buff,abc) 相当于 strcpy(buff,“abc”)

    #define fun(arg)    my##arg
//fun(ABC)  相当于 myABC

    #define fun(a,b)    a=#@b
//fun(x,y) 相当于 x='y'
前方高能:<&&宏函数&&函数>区别


宏和函数的区别:

       1. 宏做的是简单的字符串替换(注意是字符串的替换,不是其他类型参数的替换),而函数的参数的传递,参数是有数据类型的,可以是各种各样的类型.
       2. 宏的参数替换是不经计算而直接处理的,而函数调用是将实参的值传递给形参,既然说是值,自然是计算得来的.宏不支持递归,函数可以,宏不支持调试,函数可以.宏对于(++、--)可能会产生副作用,函数不会.
       3. 宏在编译之前进行,即先用宏体替换宏名,然后再编译的,而函数显然是编译之后,在执行时,才调用的.因此,宏占用的是编译的时间,而函数占用的是执行时的时间.
       4. 宏的参数是不占内存空间的,因为只是做字符串的替换,而函数调用时的参数传递则是具体变量之间的信息传递,形参作为函数的局部变量,显然是占用内存的.
       5. 函数的调用是需要付出一定的空间开销的,因为系统在调用函数时,要保留现场,然后转入被调用函数去执行,调用完,再返回主调函数,此时再恢复现场


          内联函数:

        所谓"内联函数"就是将很简单的函数"内嵌"到调用他的程序代码中,只样做的目的是为了避免上面说到的第5,目的旨在节约下原本函数调用时的空间开销.但必须注意的是:作为内联函数,函数体必须十分简单,不能含有循环、条件、选择等复杂的结构,否则就不能做为内联函数了。事实上,即便你没有指定函数为内联函数,有的编译系统也会自动将很简单的函数作为内联函数处理;而对于复杂的函数,即便你指定他为内联函数,系统也不会理会的。

 函数和宏函数的区别:

         宏函数占用了大量的空间,而函数占用了时间。大家要知道的是,函数调用是要使用系统的栈来保存数据的,如果编译器里有栈检查选项,一般在函数的头会嵌入一些汇编语句对当前栈进行检查;同时,CPU也要在函数调用时保存和恢复当前的现场,进行压栈和弹栈操作,所以,函数调用需要一些CPU时间。

  宏函数仅仅作为预先写好的代码嵌入到当前程序,不会产生函数调用,所以仅仅是占用了空间 .


小结:

        函数体量很小时,为了减小系统的开销时间,可以使用宏函数,而函数体比较复杂(需要递归、循环、判断、选择等...)的
情况下,使用函数来定义可以避免宏函数定义带来的副作用。

                         不足之处->望以斧正!
                                  -----end-----

猜你喜欢

转载自blog.csdn.net/qq_41035588/article/details/80112411
今日推荐