关于C语言之字符串拼接(堆与栈)

 C/C++  关于C语言之字符串拼接(堆与栈)已关闭评论
12月 092016
 

且看一个demo:

问题: 如何在errstr信息前面添加一个HOSTNAME 环境变量信息?

  1. 考虑到errstr有可能写到标准错误,也有可能写到标准输出,也有可能根本就不输出,所以,提前输出HOSTNAME 信息显然不合适
  2. 考虑到引用errstr的地方确实不少,最好一开始就拼接HOSTNAME到该errstr 上面去,那么如何拼接呢?

如果是在脚本语言或者带有gc的语言中,完全可以直接在errstr变量前面拼接那个动态获取到的环境变量,如:

但是c中却不能这样,为什么呢?字符串拼接的函数不是有的吗,如:strcat;

事实却并非如此简单,为什么呢?

上面的errstr变量是存储在栈上的,不需要考虑free的问题,原作者考虑到后续一大堆复杂的if分支,如果把errstr放在堆上,处处要考虑是不是该把errstr free掉,得死多少脑细胞啊!

对于HOSTNAME是个运行时的信息,显然没法放到栈上,如果非要和errstr拼接起来的话,errstr必须在堆上,即要动态的malloc,由此可见,对于脚本语言来讲,一个非常简单的逻辑,在C中却如此的麻烦

 

解决办法:

  1. 为了既不需要free,又能拼接字符串,可以定义一个字符数组,如: errstr[255],然后,把需要的信息加进去;为了避免信息太多而不小心越界,可以使用snprintf函数,自动丢弃超长的部分
 Posted by at 下午 5:24

c++之多态与虚函数

 C/C++  c++之多态与虚函数已关闭评论
7月 012016
 

多态玩的就是虚

什么是多态?
函数的形参中定义基类的情况,当然,这里的基类不一定是爷爷类,父亲类也可以,当实际调用时传递的如果是子类,那么,运行时会检查要调用的类的方法在基类(因为形参是基类,所以要参考基类)中是否virtual的,如果不是virtual的,则直接执行基类中的定义(即使当前确实是子类的实例,也不会执行子类的该方法,换言之,就是不允许覆盖,这就是virtual存在的意义,某些语言是直接覆盖的,没法选择不覆盖),如果是virtual的,则根据继承链向下检查,直到查到该方法的最后一个实现,哪怕继承链中的某些子类没有明确写virtual关键字也没关系(换言之,virtual属性是自动、强制继承的);具体实现上可能不是一个一个查,但至少逻辑上是这样的

虚函数

就是允许覆盖,多态的实现方式

纯虚函数

就是没有函数的定义,只有声明,子类想不覆盖都不行,除非子类自己不创建对象,期待孙类的继承;

语法上来讲,函数不定义是不行的,但是纯虚函数就是不定义,所以必须明确说明不定义,即: =0 ,如下: (没有 =0 是不行的)

抽象类与接口

c++中没有抽象类,也没有接口,更没有abstract、interface、implements等关键字,有的只有class和virtual

如果一个类中包含了纯虚函数,则该类自然为抽象类;

如果一个类中只包含纯虚函数,则该类相当于接口;

 Posted by at 下午 1:11

C语言中的可变参数

 C/C++  C语言中的可变参数已关闭评论
6月 202016
 

参考: http://www.tutorialspoint.com/c_standard_library/c_macro_va_start.htm  (这的代码可以执行的哦)

 

指南站: http://www.tutorialspoint.com

 Posted by at 下午 4:00

pack in c

 C/C++  pack in c已关闭评论
5月 172015
 

 

 

 Posted by at 下午 11:08

C语言中的static关键字

 C/C++  C语言中的static关键字已关闭评论
12月 312014
 

下面验证我昨天问你的一个问题:

1.c 中调用了 2.c 中的一个static函数;

这里完全可以, gcc –o test 1.c    ; 2.c 是多余的,因为1.c中include了2.c了

 

可能是我哪里错了;

把2.c 编译成一个动态的so文件,改so文件依然导出了这个static的a函数

):

  1. 定义和声明是两个概念
    1. 如果包含了定义的文件,则可以使用static 定义的函数的
    2. 如果包含的是声明的文件(就是都文件),则编译的时候必然需要找到一个外部的该符号
    3. 如果使用static定义的,则,不管编译成 .o 文件还是 .so 文件,该符号是不导出的,外部就是没法用的
  2. 一般来讲
    1. .c 文件和 .h 文件对应出现,.h 中声明外部可以使用的函数,显然不会把static的函数写到.h 中的
    2. 每个 .c 文件都单独编译成一个.o 文件,此时 static 的函数就已经被处理的外部不可见了
 Posted by at 下午 3:03

如何用GDB调试没有符号的程序

 C/C++, Linux & Unix, 程序设计  如何用GDB调试没有符号的程序已关闭评论
6月 252014
 

缘起

gcc编译程序的时候,如果没有使用-g选项,则没法调试,如果使用了-g选项,则debug信息太多,不适合线上使用,该怎么办?

解决办法

gcc的时候把符号信息放到单独的文件中,二进制文件中只保留符号文件的地址和校验值,调试的使用,把符号文件放到指定地址就OK了

 基本命令

1. 编译文件

gcc -g a.out

2. 生成debug信息文件

objcopy  –only-keep-debug a.out a.debug

3. 去掉a.out 中的调试信息

strip a.out

4. 将调试文件的名字添加到a.out 中

objcopy –add-gnu-debuglink=a.debug a.out

5. gdb调试的时候,可以通过 set debug-file-directory dir-of-debug-file  命令设置debug文件所在的目录,当然,也可以通过 symbol-file  debug-file 来读取调试符号

6.  调试信息文件究竟是个啥?

#file a.debug
a.debug: ELF 64-bit LSB executable, AMD x86-64, version 1 (SYSV), dynamically linked (uses shared libs), not stripped

似乎和原来的可执行文件没太大差别

 

相关资料:

http://www.sourceware.org/gdb/onlinedocs/gdb/Separate-Debug-Files.html

http://en.wikipedia.org/wiki/Debug_symbol

 

 Posted by at 下午 4:12

about extern “C”

 C/C++, Linux & Unix  about extern “C”已关闭评论
12月 212013
 

一般的cpp的都文件这么写:

这样的头文件是准备给C用的,符号不做修饰

 

 Posted by at 下午 9:05

关于GNU编译器的优化

 C/C++, Linux & Unix  关于GNU编译器的优化已关闭评论
12月 212013
 

缘起

闲的了

参考资料: http://www.ciselant.de/projects/gcc_printf/gcc_printf.html

 

我的g++的测试:

这里是把 printf 给优化成了puts了, 即使 -O0 也是给优化的

gcc

 

疑问

当c++ 中使用c的头文件时,一般是要如下方式引用:

extern “C” {

..

}

为什么上面例子中include的几个头文件都不需要 extern “C”  却能正常工作呢?

 

关于extern “C” 的参考资料:

http://www.cplusplus.com/reference/clibrary/

http://www.cnblogs.com/skynet/archive/2010/07/10/1774964.html

 

 Posted by at 下午 8:50

How to load debug symbols with GDB

 C/C++, Linux & Unix  How to load debug symbols with GDB已关闭评论
8月 072013
 

转: http://marcioandreyoliveira.blogspot.jp/2008/03/how-to-debug-striped-programs-with-gdb.html

My friend Wanderley asked me if it is possible to tell GDB to load debuging symbols from some file and use it to help debuging a program that doesn’t have them.

Yes. It is.

There are two solutions to this question.

I going to explain the first solution in this post. The other solution I will explain in the next post.

You can load debuging information from an debug enabled version of executable file.

In order to better explain the first solution, I will setup my sample environment as follows:

  • released.c: source code of the program we wish to debug (listing 1).
  • ~/estudo/: Source code of our program will be put here.
  • ~/local/bin: The stripped off version of binary program will stay here.
  • ~/local/symbols: In this place are all files that contain debuging information.

Listing 1 – sample program source code

I have two versions of the program: with and without debuging information.

1 – You compile your program with debug information. In our sample:

gcc -Wall -g -release release.c <ENTER>

2 – You make a copy of your program. In our sample:

cp release release.full <ENTER>

3 – You strip off debuging information:

strip -s release <ENTER>

As you can see on Figure 1, we have two programs. released.full has debuging symbols but release doesn’t have them.

[nosym_metodo1_fig1.png]
Figure 1

4 – Move file release to ~/local/bin/:

mv release ~/local/bin <ENTER>

5 – Move file released.full to ~/local/symbols/

mv release.full ~/local/symbols <ENTER>

6 – Go to directory ~/local/bin

cd ~/local/bin <ENTER>

7 – Run GDB:

gdb ./release <ENTER>

8 – Try list command to see that release executable file doesn’t have symbols in it.

Note: if the program was already running you could get its PID then attach GDB to it.

Figure 2 shows us two windows. The first one shows that our executable file has no debug information. In the other window we can see thatrelease is not yet loaded.

Figure 2 – executable file named release is loaded by GDB but it is not yet running.

9 – Let GDB to load symbols from executable file named release.full. This binary version of our program has all symbols that we need to debug.

Please notice that GDB will not replace the release executable byrelease.full version of our program. It will just import symbols fromrelease.full into release debugging session.

But GDB needs to know in advance where it must put the symbols it will load. How can you determine the correct memory address?

It is quite simple. You issue command maint inside GDB:

maint info sections

Then you look for .text section. The address that is in the first column is what you want. In our sample, it is 0x08048320. See figure 3.

Figure 3 – looking for .text section address

10 – The next step is to instruct GDB to load debug symbols into .text section. To achieve it you do this:

add-symbol-file ~/local/symbols/release.full <.text section address>

In our sample it means to type:

add-symbol-file ~/local/symbols/release.full 0x08048320

From now on you can debug your program as usual.

Figure 4 shows us that debugging symbols where imported successfully and that now the list command (abbreviated as l) shows us the program source code.

Figure 4 – now our GDB session has debuging symbols

As you can see in figure 5, I set a break point at line 17 and I ran the program that stopped there. Then I printed i variable.

In the other terminal I issued ps command. It was done just to show you that the only program running was release executable. There is no instance of release.full program.

Figure 5 – debugging session.

I hope this post will make your life easier. In the next time I will teach you another way to import debugging symbols.

 Posted by at 下午 11:55