Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

What are the advanced uses of the C language?

2025-01-18 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

Shulou(Shulou.com)06/02 Report--

This article mainly explains "what are the advanced uses of C language". Friends who are interested may wish to have a look. The method introduced in this paper is simple, fast and practical. Now let the editor take you to learn "what are the advanced uses of the C language"?

Plastic overflow and lifting

Most C programmers think that basic plastic operations are safe, but they are not. Take a look at the following example, what do you think the output is?

Int main (int argc, char** argv) {long I =-1; if (I

< sizeof(i)) { printf("OK\n"); } else { printf("error\n"); } return 0; } 当一个变量转换成无符号整形时,i的值不再是-1,而是 size_t的最大值,因为sizeof操作返回的是一个 size_t类型的无符号数。在C99/C11标准里写道: "If the operand that has unsigned integer type has rank greater orequal to the rank of the type of the other operand, then the operandwith signed integer type is converted to the type of the operand withunsigned integer type." 在C标准里面 size_t至少是一个 16 位的无符号整数,对于给定的架构 size_t 一般对应long,所以sizeof(int)和size_t至少相等,这就带来了可移植性的问题,C标准没有定义 short, int,long,longlong的大小,只是说明了他们的最小长度,对于 x86_64 架构,long在Linux下是64位,而在64位Windows下是32位。一般的方法是采用固定长度的类型比如定义在C99头文件stdint.h中的uint16_t,int32_t,uint_least16_t,uint_fast16_t等。 如果 int可以表示原始类型的所有值,那么这个操作数会转换成 int,否则他会转换成 unsigned int。下面这个函数在 32 位平台返回 65536,但是在 16 位系统返回 0。 uint32_t sum() { uint16_t a = 65535; uint16_t b = 1; return a+b; } 对于char 类型到底是 signed 还是 unsigned 取决于硬件架构和操作系统,通常由特定平台的 ABI(Application Binary Interface) 指定,如果是 signed char,下面的代码输出-128 和-127,否则输出 128,129(x86 架构)。 char c = 128; char d = 129; printf("%d,%d\n",c,d);内存管理和分配 malloc 函数分配制定字节大小的内存,对象未被初始化,如果 size 是 0 取决与系统实现。malloc(0)返回一个空指针或者 unique pointer,如果 size 是表达式的运算结果,确保没有整形溢出。 "If the size of the space requested is 0, the behavior isimplementation- defined: the value returned shall be either a nullpointer or a unique pointer." size_t computed_size; if (elem_size && num >

SIZE_MAX / elem_size) {errno = ENOMEM; err (1, "overflow");} computed_size = elem_size*num

Malloc will not initialize the allocated memory. If you want to initialize the newly allocated memory, you can use calloc instead of malloc. In general, when assigning elements of the same size to a sequence, use calloc instead of using expressions to calculate the size. Calloc will initialize the memory to 0.

Realloc is used to resize objects that have allocated memory. If the new size is larger, the extra space is not initialized. For example, if the pointer provided to realloc is empty, realloc is equivalent to malloc. If the original pointer is not null and new size is 0, the result depends on the specific implementation of the operating system.

In case of failure realloc shall return NULL and leave provided memoryobject intact. Thus it is important not only to check for integeroverflow of size argument, but also to correctly handle object size ifrealloc fails.

The following code will show you how to use malloc,calloc,realloc,free:

# include # define VECTOR_OK 0 # define VECTOR_NULL_ERROR 1 # define VECTOR_SIZE_ERROR 2 # define VECTOR_ALLOC_ERROR 3 struct vector {int * data; size_t size;}; int create_vector (struct vector * vc, size_t num) {if (vc = = NULL) {return VECTOR_NULL_ERROR;} vc- > data = 0; vc- > size = 0 / * check for integer and SIZE_MAX overflow * / if (num = = 0 | | SIZE_MAX / num

< sizeof(int)) { errno = ENOMEM; return VECTOR_SIZE_ERROR; } vc->

Data = calloc (num, sizeof (int)); / * calloc faild * / if (vc- > data = = NULL) {return VECTOR_ALLOC_ERROR;} vc- > size = num * sizeof (int); return VECTOR_OK;} int grow_vector (struct vector * vc) {void * newptr = 0; size_t newsize; if (vc = NULL) {return VECTOR_NULL_ERROR } / * check for integer and SIZE_MAX overflow * / if (vc- > size = = 0 | | SIZE_MAX / 2

< vc->

Size) {errno = ENOMEM; return VECTOR_SIZE_ERROR;} newsize = vc- > size * 2; newptr = realloc (vc- > data, newsize); / * realloc faild; vector stays intact size was not changed * / if (newptr = = NULL) {return VECTOR_ALLOC_ERROR;} / * upon success; update new address and size * / vc- > data = newptr; vc- > size = newsize; return VECTOR_OK } avoid major mistakes

Using uninitialized variables, C language requires all variables to be initialized before use, the use of uninitialized variables will result in defined behavior, which is different from C++, C++ ensures that all variables are initialized before use, Java tries to ensure that variables are initialized before use, such as class basic data members will be initialized to default values.

Free error calls free on null pointers, free on pointers that are not assigned by the malloc family function, or free again on pointers that have already called free. Initializing the pointer to NULL reduces errors. GCC and Clang compilers have the-Wuninitialized option to display warnings for uninitialized variables, and do not use the same pointer for static and dynamic variables.

Char * ptr = NULL; void nullfree (void * * pptr) {void * ptr = * pptr; assert (ptr! = NULL) free (ptr); * pptr = NULL;}

3. Dereference of empty pointer, array out of bounds access

Dereferencing NULL pointers or free'd memory, array out-of-bounds access, is an obvious error, in order to eliminate this error, the general approach is to increase the array out-of-bounds check function, such as Java array has the subscript check function, but this will bring serious performance costs, we have to modify ABI (application binary interface), so that each pointer follows its range information, in the numerical calculation cost is terrible.

4. Violation of type rules

Cast the int × pointer to float ×, and then dereference it. In C #, it will cause undefined behavior,C to specify that this type of conversion requires the use of a reinterpret_cast function in memset,C++ for conversion between unrelated types, reinterpret_cast (expression).

Prevent memory leaks

Memory leaks occur when dynamic memory that is no longer used by the program is not released, which requires us to grasp the scope of dynamically allocating objects, especially when to call free to free memory. The common centralized methods are as follows:

When the program starts, it allocates the heap memory needed when the program starts, and when the program exits, it gives the released tasks to the operating system. This method is generally applicable to the kind that exits immediately after the program is run.

Use variable length array (VLA) if you need a variable length array and the scope is in the function, the variable length array can help you, but there is also a limitation. The memory size of a variable length array in a function is generally no more than a few hundred bytes. This digital C standard is not clearly defined. It is best to allocate memory to the stack. The maximum VLA memory allowed on the stack is SIZE_MAX. Mastering the stack size of the target platform can effectively prevent stack overflow.

Using reference counting is a good way to manage memory, especially when you don't want your defined objects to be copied, add 1 to each assignment and subtract 1 every time you lose a reference. when the reference count is equal to 0, we think that the object is no longer needed, we need to free the memory occupied by the object, because C does not provide automatic destructors We have to release memory manually. Look at an example:

# include # include # define MAX_REF_OBJ # define RC_ERROR-1 struct mem_obj_t {void * ptr; uint16_t count;}; static struct mem_obj_t references [Max _ REF_OBJ]; static uint16_t reference_count = 0; / * create memory object and return handle * / uint16_t create (size_t size) {if (reference_count > = MAX_REF_OBJ) return RC_ERROR; if (size) {void * ptr = calloc (1, size) If (ptr! = NULL) {references [reference _ count]. Ptr = ptr; references [reference _ count]. Count = 0; return reference_count++;}} return RC_ERROR;} / * get memory object and increment reference counter * / void* retain (uint16_t handle) {if (handle)

< reference_count && handle >

= 0) {references [handle] .count +; return references [handle] .ptr;} else {return NULL;}} / * decrement reference counter * / void release (uint16_t handle) {printf ("handle\ n"); if (handle)

< reference_count && handle >

= 0) {struct mem_obj_t * object = & references [handle]; if (object- > count ptr); reference_count--;} else {printf ("decremented\ n"); object- > count--;}

The C++ standard library has an auto_ptr smart pointer, which can automatically release the memory of the objects indicated by the pointer. The C++ boost library has a boost::shared_ptr smart pointer, which has built-in reference counting and supports copy and assignment. See the following example:

"Objects of shared_ptr types have the ability of taking ownership of a pointer and share that ownership: once they take ownership, the group of owners of a pointer become responsible for its deletion when the last one of them releases that ownership."

# include # include int main () {/ / Basic useage boost::shared_ptr p1 (new int (10)); std::cout

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Development

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report