admin管理员组

文章数量:1573678

最近在看《C++ 编程思想》,其中指针简介中有简单介绍查看变量和函数的内存分配,发现在输出函数地址的时候出现地址值总是1。代码如下:

#include <iostream>

using namespace std;

void f(int oo){
}
void j(int pp){
cout << pp << endl;
}
void k(int qq){
    cout << qq << endl;
}

int main(){
cout << "f():" << f << endl;
cout << "j():" << j << endl;
cout << "k():" << k << endl;
}


代码中出现警告如下:

警告: ‘void f(int)’的地址总是等价为‘true’ [-Waddress]
 警告: ‘void j(int)’的地址总是等价为‘true’ [-Waddress]
警告: ‘void k(int)’的地址总是等价为‘true’ [-Waddress]


在忽略警告的情况下运行结果如下:


f():1
j():1
k():1

如果将代码中函数地址强制转换成long型可以正确输出,如下:


#include <iostream>

using namespace std;

void f(int oo){
}
void j(int pp){
cout << pp << endl;
}
void k(int qq){
    cout << qq << endl;
}

int main(){
cout << "f():" << (long)f << endl;
cout << "j():" << (long)j << endl;
cout << "k():" << (long)k << endl;
}


输出结果如下:

f():4196420
j():4196429
k():4196470

先解释一下经过(long)强制转换以后是十进制输出,另外我是在linux环境下的64位机器,long型变量为64位,编译器为g++.


问了很多人,也在网上搜了一篇帖子跟这个有关系,会在最后附上参考的帖子地址。


最后总结为c++中的cout<< 这个输出函数是经过重载过的,支持的输出类型不多,我察看了一下ostrem文件,operator<<重载的只有简单的几种内置类型,并没有像上述中的输出类型 void (*)(int), 需要进行转换,

所以,解决办法有两种:

第一:强制转换为整型,即(long)f;为了便于我们看懂,这里转换成十进制。

第二:重载一个类似的输出operator<<,其中类型为void (*)(int).


 另外,还可以通过C语言的printf来输出,如下:

#include <iostream>
#include <cstdio>


using namespace std;


void f(int oo){
}
void j(int pp){
cout << pp << endl;
}
void k(int qq){
    cout << qq << endl;
}


int main(){
printf("f():%p\n",f);
printf("j():%p\n",j);
printf("k():%p\n",k);
}


这样也能正确输出结果。下面列一下printf("%p",m)的用法:

        %p:   按16进制显示指针型数据  这里的指针型参数为  void *, TYPE * (TYPE 为任意类型),直接输出指针值。所以printf就不存在cout<<的问题。


听说高手都用printf,可见printf的强大,以下列出C/C++ 的 “printf 族”函数(printf, sprintf, fprintf, ...)的一般格式:


Xprintf(XXX, const char * format, ...)

其中 X 代表 "s", "f", "" 之类,XXX 代表 format 之前的参数(如 char * buf, FILE * fp...)

其中的 format 叫格式字符串,其定义是很通用的,在其它许多语言中也广泛使用。
"..." 是可变参数,对应的实参称为“输入参数”,其类型是由 format 规定的,而且必须由程序员自己保证正确(如果与 format 不一致,可能会导致意外错误)。

格式字符串的由两种成分组成:


1. 平直成分 ———— 直接拷贝到输出流(屏幕、结果字符串、文件等)中
2. 格式描述子 ———— 按规定的方式以格式字符串后的实参中的对应项进行替换

如 printf("Give me a %s", "kiss") 中,"Give me a " 是平直成分,"%s" 是格式描述子,表示用后面对应位置的输入参数("kiss")取代其所在位置。

格式描述子的一般格式:

% [flags] [width] [.prec] [F|N|h|l|L] type_char

"%" 为开头标记,后面的项目可以组合,其中 type_char 必须有,而 [] 中的成分可以省略(表示用默认设置)

flags -- 规定输出对齐、正负号、小数点、小数后的“0”、进制(八进制/十六进制)
        "-" 输出左对齐,右边补空格
        "+" 表示明确输出正负号(即使是正数)
        "#" 跟后面的字符配合表示高级格式(略)

width -- 规定输出宽度
        整数 n 表示如果默认输出少于 n 个字符,就用空格填充到 n 个字符(如果 flags="-",则右填充,否则左填充)
        0n 表示如果默认输出少于 n 个字符,就在输出的左边填充“0”到 n 个字符
        "*" 表示用后面对应位置的输入参数(必须是一个整数)指定宽度

.prec -- 指定输出精度
        .0 表示不输出小数部分(对浮点数)

        .n 表示输出 n 位小数(对浮点数,固定格式)或有效数字(对浮点数,科学计数法),或者最多输出 n 个字符(对字符串)

F|N|h|l|L -- 指定输入参数的大小(Size),与参数类型(Type)有关

        F       p s         远指针 (far XXX *)
        N       n   A       近指针 (near XXX *)
        h       d i o       short int
        l       d i o       long int
        l       e E f       double
        L       e E f g G       long double
        L       d i o u x X     __int64

        h       c C A       单字节字符(single-byte character)
        l       c C A       宽字符(Wide character)
        h       s S A       单字节字符串(single-byte character string)
        l       s S A       宽字符串(Wide character string)

type_char -- 指定输入参数的类型

        d,i         signed int/short/long (具体是哪个由前面的“F|N|h|l|L”决定)
        u           unsigned int/short/long
        x,X         十六进制 unsigned int/short/long, x 对应 "abcdef", X 对应 "ABCDEF"

         f           float/double/long double, 固定格式,如 123.456
        e,E         float/double/long double, 科学计数法,如 1.23e+30, 4.56E+12
        g,G         float/double/long double, 根据具体数值自动选择固定格式或科学计数法
        c           char
        s           char *
        %           输出 "%" 本身(而不是当作格式描述子的开头标记),例如 printf("%%45") 输出 "%45"
        n           用一个 int * 指向的 int 表示输出的字符数
        p           void *, TYPE * (TYPE 为任意类型),直接输出指针值



参考帖子地址:http://bbs.chinaunix/forum.php?mod=viewthread&action=printable&tid=1423184


本文标签: 函数入口地址