我非常适合使用Java和C#等语言进行编码,但我需要将C用于项目(因为低级OS API调用)并且我在处理指针和内存管理方面遇到了一些困难(如{{ 3}})
现在我基本上是在输入代码并将其提供给编译器以查看它是否有效。这对我来说感觉不对。任何人都可以向我指出很好的资源来理解来自托管语言的指针和内存管理吗?
答案 0 :(得分:5)
答案 1 :(得分:3)
你已经找到的好资源之一,所以。
当然,你正在编写所有警告,不是吗?
在实践中学习很大程度上取决于编译器的质量以及他为您提供的警告/错误。我在linux / POSIX世界中发现的最好的是clang。很好地追踪错误的起源,并告诉你很好地缺少头文件。
答案 2 :(得分:1)
一些提示:
C相当于
Integer i = new Integer();
i=5;
是
int *p;
p=malloc(sizeof(int));
*p=5;
答案 3 :(得分:1)
学习使用gdb逐步执行代码并打印变量值(使用-g编译以启用调试符号)。
使用valgrind检查内存泄漏和其他相关问题(如堆损坏)。
答案 4 :(得分:1)
C语言没有做任何你没有明确告诉它的事情。
没有自动为你调用的析构函数,这既好又坏(因为析构函数中的错误可能很痛苦)。
获得某种自动析构函数行为的一种简单方法是使用作用域来构造和破坏事物。这可能会变得很难看,因为嵌套的范围会使事情进一步向右移动。
if (var = malloc(SIZE)) { // try to keep this line
use_var(var);
free(var); // and this line close and with easy to comprehend code between them
} else {
error_action();
}
return; // try to limit the number of return statements so that you can ensure resources
// are freed for all code paths
尝试尽可能地让代码看起来像这样会有所帮助,尽管并非总是可行。
制作一组初始化对象的宏或内联函数是个好主意。还可以创建另一组函数来分配对象的内存并将其传递给初始化函数。这允许容易地初始化本地和动态分配的对象。类似析构函数的类似操作也是一个好主意。
在许多情况下使用OO技术是很好的做法,而在C中这样做只需要更多的输入(但允许更多的控制)。推杆,getter和其他辅助函数可以帮助保持对象处于一致状态,并减少发现错误时必须进行的更改,如果可以保持接口相同。
您还应该查看perror
函数和errno
“变量”。
通常你会想要避免使用C中的异常之类的东西。我通常也试图在C ++中避免使用它们,并且只将它们用于非常糟糕的错误 - 那些不应该发生的错误。避免它们的主要原因之一是没有在C中神奇地产生的析构函数调用,因此非本地GOTO通常会泄漏(或以其他方式搞乱)某种类型的资源。话虽如此,C中有些东西提供了类似的功能。
C中的机制之类的主要异常是setjmp
和longjmp
函数。从代码中的一个位置调用setjmp
并传递一个(不透明的)变量(jmp_buf),该变量稍后可以传递给longjmp
。当调用longjmp
时,它实际上不会返回给调用者,而是返回之前称为setjmp
的jmp_buf。 setjmp
将返回longjmp
调用指定的值。定期致电setjmp
会返回0。
其他异常功能更具特定于平台,但包含信号(有自己的问题)。
其他需要注意的事项是:
assert
宏,当参数(某种逻辑测试)失败时,可用于导致程序退出。当您assert
之前#define NDEBUG
时,#include <assert.h>
的呼叫会消失,因此经过测试后,您可以轻松删除断言。这非常适合在解除引用之前测试NULL指针,以及其他几个条件。如果条件失败,则assert
会尝试打印失败测试的源文件名和行号。
abort
函数导致程序退出失败而不执行调用exit
所做的所有清理工作。这可以通过某些平台上的信号来完成。 assert
致电abort
。