1. 程式人生 > >【異常/錯誤處理系列】C語言如何實現異常處理

【異常/錯誤處理系列】C語言如何實現異常處理

前言:

    不管是哪門程式語言,在coding過程中,我們都會遇到一個很頭痛的問題,就是如何處理函式的返回值和異常。函式返回值傳統的處理的方法是使用If/else。但對於有返回碼的函式,需要寫“無數”的if分支,程式碼很難看,也不好維護。異常處理更是頭痛,一旦發生,只有檢視resetlog,對於網路類異常,或者庫中出現的異常,呼叫者也不知道如何處理。高階語言中,都有try/catch/finally的語法,用於異常處理。但是在C語言中,沒有相應的支援。通過丟擲異常,並讓能處理該異常的上層函式處理,是比較符合自然邏輯的方法。如果能夠在C語言中支援,就非常好了。下面的文章,介紹瞭如何實現一個自定義的c異常處理支援的過程。值得參考。該文章幾個要點值得注意:

1.  目前針對C的異常處理機制,已經有開源(比如GitHub)實現,如果專案中有需要,可以下載並根據專案定製。

2. C/C++都借用的setjump/longjump實現異常處理。可能不準確,因為C++中還有很多runtime支援。C++的異常處理具體實現方法還有語言級別的支援。後續會進一步學習。

3. 異常處理時,需要跳轉到異常處理函式。當前棧內的內容如何處理,需要視情況而定。C++中,由於支援析構,所以棧中的內容要逐步清理。特別是變數。針對函式,要看需求,是否需要逐級返回,還是直接跳轉到頂層。以下文章,由於不再需要棧中內容,所以直接出棧,拋棄了棧中的內容。針對Java,由於需要列印呼叫棧,估計還需要拷貝棧中的內容。

4. setJump可以儲存函式呼叫前上下文是機制的關鍵,因為只有這樣,當呼叫longjump時,可以返回到呼叫前的狀態,並根據setjump的不同返回值,呼叫異常處理函式。

以下內容轉載自:http://www.on-time.com/ddj0011.htm,避免國內使用者無法檢視,故複製如下。如果原作者有版權問題,請聯絡我刪除。

Exception Handling in C without C++

Clean error handling without overhead

by Tom Schotland and Peter Petersen

Error handling is an important issue in embedded systems, and it can account for a substantial portion of a project's code. We were faced with this issue during the design of RTFiles, the embedded filesystem component of On Time RTOS-32, our Win32-compatible RTOS for 32-bit x86 targets. The core filesystem is portable with a C function API to the application and a device-driver interface below it. Typically, errors can occur in device drivers and must be reported to the application with suitable return codes, so errors must travel through the complete core filesystem.

The classic C approach to this problem is return codes. Each function returns a value indicating success or failure. However, with a nontrivial function call hierarchy, this approach clutters the code significantly. Every function must check the return code of every function call it makes and take care of errors. In most cases, the function will merely pass any errors back up to its caller. RTFiles has several hundred internal functions and a call hierarchy up to about 15 levels deep, so this approach would have been a nightmare to maintain.

Programming languages such as Ada or C++ address this issue with exceptions. Exceptions make it easy to separate error handling from the rest of the code. Intermediate functions can completely ignore errors occurring in functions they call, if they can't handle them anyway. Exceptions are much easier to maintain than error return codes, so we definitely wanted to use them for RTFiles. Unfortunately, we had to write RTFiles in C, and not C++ or Ada, for portability. RTFiles must support compilers without C++ support.

Another issue is overhead and reliability. C++ exception handling needs a lot of run-time system support routines, which might add too much code to a small embedded system. C++ exceptions are objects dynamically allocated from the heap, but many embedded systems do not want to use any dynamic memory allocation to avoid heap fragmentation and out-of-heap-space problems. For example, what would happen if an RTFiles device driver throws a disk-write-protection exception, and the heap allocation called by throw throws an out-of-memory exception?

The solution to the problem is to implement a simple exception-handling library in C with the following goals:

  • No dynamic memory allocation.
  • Robust (the exception handling library itself must not fail).
  • Must support both exception-handlers and finally-handlers.
  • Reentrant for multitasking applications.

In this article, we describe how we designed and implemented our exception-handling library, demonstrate how it is used, and compare it to C++ exception handling. The complete source code is available through the DDJ Resource Center accessible to registered users of www.ddj.com.

   jmp_buf jumper;

   int SomeFunction(int a, int b)
   {
      if (b == 0) // can't divide by 0
         longjmp(jumper, -3);
      return a / b;
   }

   void main(void)
   {
      if (setjmp(jumper) == 0)
      {
         int Result = SomeFunction(7, 0);
         // continue working with Result
      }
      else
         printf("an error occured\n");
   }

Example 1: A simple error-handling approach based on setjmp() and longjmp().

Handling Exceptions in C

The basic function of exception handling is to transfer control to an exception-handler when an error occurs, where the handler resides somewhere higher up in the current function call hierarchy. Standard C has a mechanism to accomplish this: setjmp() and longjmp(). Example 1 shows a simple implementation of error handling based on setjmp()/longjmp(). However, this example is a little too simple. It relies on a single global variable called "jumper," which contains the information where the exception handler is. However, we need many different exception handlers in different functions, so how will SomeFunction() know which jumper to use? Another issue is multitasking. Each task will have its own call hierarchy and thus needs its own jumper or set of jumpers.

What we really need is a dynamically linked list of exception handler records. Such a record will contain a jmp_buf structure and supplemental information (for example, whether an exception has been raised, has it been handled, what is its error code, and so on). Each function that defines an exception-handler adds such a record to the list and removes it from the list when it returns. The exception-handler records are allocated in the function's stack frame since we do not want to use the heap.

To make the whole thing reentrant, a separate list root is maintained per task. Multitasking operating systems will usually provide some mechanism to maintain per-task values. For example, Win32 has Task Local Storage (TLS), and RTKernel-32, the real-time kernel component of On Time RTOS-32, has both  Win32 TLS and its own Task User Data. TLS allows an application to allocate a pointer value for every task (even for those that have not been created yet). At run time, this value can be set and retrieved by the current task. Our exception handling library uses TLS to store the exception-handler list root pointers. If used in a single-task environment, the list root can simply be implemented as a single global variable.

   #define DIVIDE_BY_ZERO -3
   int SomeFunction(int a, int b)
   {
      if (b == 0) // can't divide by 0
         XRaise(DIVIDE_BY_ZERO);
      return a / b;
   }

   void main(void)
   {
      XRecord XData;
      XLinkExceptionRecord(&XData);
      switch (setjmp(XData.Context))
      {
         case 0: // this is the code block
            {
               int Result = SomeFunction(7, 0);
               // continue working with Result
            }
            break;
         case DIVIDE_BY_ZERO:
            printf("a division by zero occurred\n");
            break;
         default:
            printf("some other error occurred\n");
            break;
         case XFINALLY:
            printf("cleaning up\n");
      }
      XUnLinkExceptionRecord(&XData);
   }

Example 2: setjmp()/longjmp()-based error handling with exception records allocated on the stack.

   void main(void)
   {
      XTRY
         case XCODE: // this is the code block
            {
               int Result = SomeFunction(7, 0);
               // continue working with Result
            }
            break;
         case DIVIDE_BY_ZERO: // handler for a
                                 specific exception
            printf("a division by zero occurred\n");
            break;
         default: // default handler
            printf("some other error occurred\n");
            break;
         case XFINALLY: // finally handler
            printf("cleaning up\n");
      XEND
   }

Example 3: This program is functionally identical to Example 2, but the details of setting up the exception handler block have been moved to macros XTRY and XEND.

Example 2 shows an improved version using exception handler records on the stack. XLinkExceptionRecord() puts the given exception-handler record onto the current task's exception-handler list and initializes it. XUnLinkExceptionRecord() removes the exception-handler record from the list. XRaise() throws an exception, which is a negative error code in RTFiles. XRaise() retrieves the top-level exception-handler record of the current task and then calls longjmp() with the given error code. This transfers control to the correct handler.

To simplify the syntax, the exception-handler library's header file defines a few macros to encapsulate building and destroying an exception-handler block. Example 3 shows the same program using these macros.

Semantic Details

One big advantage of a home-grown exception handling library is that we can define the semantics to best fit the needs of our application. For example, the most common case in RTFiles is that a function cannot handle an error, but some cleanup action is required. Typically, some global data structures of the filesystem are protected on entry to the filesystem using semaphores. We must ensure that such semaphores are released no matter how the function is left (through a normal return statement or through an exception). We thus reserved a special exception code (-1, defined as XFINALLY), which shall always be raised exactly once when an XTRY block is left. Such a finally-handler is not supported by C++ exception handling.

Another difference from C++ exceptions is that executing an exception-handler does not automatically complete handling of the exception. If the handler does not explicitly call function XHandled(), the exception-handling library will continue to pass the exception to handlers higher up in the list (called "exception propagation" or "stack unwinding"). We decided on these semantics because they reflect the typical case in RTFiles. However, in other applications, this could be handled differently, such as by using C++ semantics where an exception is considered handled once an exception handler has been invoked.

The RTFiles API consists of C functions that all return integer values. Positive values indicate success and negative values indicate errors. For example, the function to open a file, RTFOpen(), will either return a valid, positive file handle or an error code such as RTF_FILE_NOT_FOUND, which is defined as -9. To keep things simple, we use the standard RTFiles error codes as exception values. This lets us automate returning correct error codes to the application. Because all RTFiles API functions contain a top level XTRY block, when leaving the block, we can simply return the current exception value. Basically, we propagate exceptions out of RTFiles by simply returning the exception value. This is implemented by the macro XEND, which returns the error code if it finds that the last exception-handler record has been removed and that a still unhandled exception is being propagated.

To implement these semantics, the exception-handling library must know the current state of processing, stored in the current top-level exception-handling record. Three states are distinguished:

  • XCode. The code body of the try block is being executed.
  • XHandling. An exception-handler is being executed.
  • XFinally. The finally block is being executed.

When an XTRY block is entered, the initial state is set to XCode by function XLinkExceptionRecord(). If the code section completes without raising any exceptions, XUnLinkExceptionRecord() is called next, which will then set the state to XFinally and execute the finally-handler. If, however, an exception is raised, XRaise() sets the state to XHandling and calls the appropriate handler. If the handler does not call XHandled() to indicate that the exception is now handled, XUnLinkExceptionRecord() executes the finally-handler and moves on to the next handler in the handler chain. This means that any code following the XTRY block will never get executed, and the current execution frame is abandoned.

Of course, this process has to stop somehow. If an exception-handler can handle the error, it will call XHandled() and normal execution will continue after the current XTRY block. If the outermost exception-handler has not handled the exception, we just pass the exception code (which is an RTFiles error code) back to the application. However, most applications will propably prefer to abort the program with a fatal error (just like C++, for example).

As long as the OS-dependent functions for TLS data are defined (in our example, we just use a single global variable), the exception library can be compiled with any ANSI C compiler. However, our goal to become independent of the C++ run-time systems has not been reached yet. Looking at the source code of typical implementations of longjmp() reveals that longjmp() references a lot of the C++ exception-handling support routines. This makes sense because C++ must ensure that all objects with a local scope are destroyed when the respective scope is left. As longjmp() can leave a local scope, it must also call the destructors of all objects going out of scope. Because we only use C in RTFiles, this functionality is not required, and we do not want longjmp() to pull in so much code we would never need. Thus, we implemented our own versions of setjmp() and longjmp(); see Listing One. The two functions, XSaveContext() and XRestoreContext(), only have to save/restore the stack frame registers, the return address, and any registers the compiler might use for register variables. By defining symbol XWIN32, our alternate functions are used by the exception-handling library instead of setjmp()/longjmp().

   XTRY
      case XCODE
         // code body
         break;
      [case ERROR_1:
         // handler for ERROR_1
         break;
         // more handlers go here
      ...]
      default:
         // handle all other errors
         break;
      case XFINALLY:
         // finally handler
   XEND or XENDX

Example 4: The basic structure of an XTRY block.

Using the C Exception Handling Library

XTRY blocks can be nested to any depth, either within a single function or across function calls. The XTRY block has a code body, any number of exception-handlers to handle specific exceptions, a single default handler to catch all other exceptions, and a finally-handler. Example 4 shows the basic structure of of an XTRY block.

The XTRY block is closed with macro XENDX or XEND. XENDX is used in functions that cannot return the error code as a return value. This is frequently the case for functions internal to RTFiles, declared as static void. If XENDX finds no outer exception-handler, it reports a fatal error. Basically, this means that a function containing an XENDX block may only be called while an XTRY block already resides on the call stack. This is the case in RTFiles, since all API functions (the only entry points to RTFiles) have XTRY blocks.

Within an XTRY block, a few exception-management functions are available. XRaise(int XValue) raises an exception with the given error code. XValue must be a value less than or equal -2, because positive values are not considered errors and -1 is reserved for the finally-handlers. XHandled() stops propagating an exception. It may only be called from an exception-handler. XReExecute() can be called by an exception-handler to execute the code body of the current XTRY block again. For example, this can be used for retries. Finally, macro XVALUE returns the value of the exception currently being processed.

There are also a few restrictions that must be observed. Due to the implementation of setjmp() and longjmp(), all local variables used within more than one part of an XTRY block (code body, exception handler, finally handler, or outside the XTRY block) must be declared as volatile. This is required by the C ANSI standard, which is explained in more detail in "Register Variables and longjmp()". Additionally, this C exception-handling library should not be mixed with C++ code within the same source file, because it could cause destructors not to be called.

How Does it Compare to C++ Exceptions?

Although C++ was never an option for RTFiles, we do want to check that our goals have been met. In particular, our C exception-handling library should have little run-time overhead, and it should need less code space than C++ exceptions. Listings Two and Three show a C and a C++ version of a benchmark program, respectively. One thing difficult to compare is the finally-handler, which is not supported by C++. In the benchmark, the finally-handler should merely increment an integer. In the C++ version, this statement has been placed in the destructor of a local class object. C++ guarantees that such a destructor is called when its object goes out of scope, regardless of the method to leave the scope.

Program Code Size Time (no throws) Time (with throws)
XBench.c 4.6k 1392 ms 1362 ms
CPPBench.cpp 35.3k 1492 ms 71343 ms

Table 1: Code sizes and benchmark results for C and C++ exception-handling compiled with Borland C++ Builder 4.0, run under Windows NT.

Table 1 lists the execution times and code sizes of both programs. Execution times are given for the case where no exceptions are thrown and for one throw per iteration. The C program has been linked with a stripped-down run-time system with C++ exception-handling support removed while the C++ version is linked with an unmodified run-time system. The tests were performed with Borland C++ Builder 4.0 for Win32 under Windows NT. While there is only a small difference in execution times when no exceptions occur, the C exception library easily outperforms C++ in all other disciplines.

Conclusion

This simple exception-handling library has been a great help in implementing RTFiles. The mechanism is easy to use, portable, uses no dynamic memory allocation, and is efficient. When used correctly (that is, when you do not call XRaise() while no XTRY block is present on the call stack), it cannot fail. In particular for embedded systems, where low resources preclude the use of C++, using the C exception-handling library can radically reduce the complexity of error handling.

Sidebar 1: Register Variables and longjmp()

Care must be taken with local variables in functions using setjmp(). In Example 5, for instance, you would expect the following program output:

   1: 1
   2: 2
   3: 3

However, with most optimizing compilers, it will be:

   1: 1
   2: 2
   3: 2
   void main(void)
   {
      jmp_buf jumper;
      int LocalVar = 1;

      printf("1: %i\n", LocalVar);
      if (setjmp(jumper) == 0)
      {
         LocalVar++;
         printf("2: %i\n", LocalVar);
         longjmp(jumper, 1);
      }
      LocalVar++;
      printf("3: %i\n", LocalVar);
   }

Example 5: Sample Program.

In particular, the incorrect result will be produced whenever the compiler chooses to allocate LocalVar as a register variable. setjmp() will save all registers used for register variables in the given jmp_buf. Even though the register variable has been incremented after the call to setjmp(), longjmp() will restore the value it had at the time of setjmp(). The only way to prevent this problem is to declare such variables as volatile. This is even required by the ANSI C standard in section 7.6.2.1.

Since the C exception-handling library uses setjmp() in its XTRY macro and calls longjmp() in macro XEND and XRaise(), all parameters and local variables of functions with XTRY blocks must be declared as volatile if their values must be preserved across the XTRY and XEND macros. This is even the case when alternate functions for context saving/restoring are used instead of setjmp()/longjmp(), since they also can only restore register variable values in effect when the context was saved.

   ; RTFEX32.ASM
   ; Copyright (c) 1998,99 On Time Informatik
   ; http://www.on-time.com/
   ; Custom context save/restore functions for C Exception Handling Library 
   ; This is what we want to implement:
   ; typedef struct {
   ;    unsigned long esi, edi, ebx, ret, ebp, esp;
   ; } XContext;
   ; int __stdcall XSaveContext(XContext * C);
   ; void __stdcall XRestoreContext(XContext * C, int Value); 

   .386

   XContext STRUC
      _esi DD ?
      _edi DD ?
      _ebx DD ?
      _ret DD ?
      _ebp DD ?
      _esp DD ?
   XContext ENDS

   _TEXT SEGMENT DWORD USE32 PUBLIC 'CODE'

   ASSUME CS:_TEXT

   PUBLIC XSaveContext
   PUBLIC [email protected]
   PUBLIC XRestoreContext
   PUBLIC [email protected]

   XSaveContext proc near
   [email protected] label near
      pop ecx                           ; ret address
      pop edx                           ; parameter C
      mov [edx+_esi], esi               ; save all required registers
      mov [edx+_edi], edi
      mov [edx+_ebx], ebx
      mov [edx+_ret], ecx
      mov [edx+_ebp], ebp
      mov [edx+_esp], esp
      xor eax, eax                      ; return code is zero
      jmp ecx                           ; and return
   XSaveContext endp

   XRestoreContext proc near
   [email protected] label near
      mov edx, [esp+4]                  ; parameter C
      mov eax, [esp+8]                  ; parameter Value, set as return value
      mov esi, [edx+_esi]               ; restore all required registers
      mov edi, [edx+_edi]
      mov ebx, [edx+_ebx]
      mov ebp, [edx+_ebp]
      mov esp, [edx+_esp]
      jmp [edx+_ret]                    ; and jump to saved context
   XRestoreContext endp

   _TEXT ENDS

   END
   // XBENCH.C
   // Copyright (c) 1998,99 On Time
   // http://www.on-time.com/
   // Benchmark for the C Exception Handling Library

   #include <windows.h>
   #include <stdlib.h>
   #include <stdio.h>

   #include <rtfex.h>

   #define DIVIDE_BY_ZERO -3  // an error code

   // some global variables to count
   // iterations, exceptions, and cleanups

   int Calls, Exceptions, Finallys;

   ///////////////////////////////////////
   int SomeFunction(int a, int b)
   // functiom which can raise an exception
   {
      if (b == 0)
         XRaise(DIVIDE_BY_ZERO);
      return a / b;
   }

   ///////////////////////////////////////
   int TestFunction(int a, int b)
   // test function containing an XTRY block
   {
      int volatile Result;
      Calls++;
      XTRY
         case XCODE:
            Result = SomeFunction(a, b);
            break;
         case DIVIDE_BY_ZERO:
            Exceptions++;
            XHandled();
            break;
         default:
            printf("unknown exception!\n");
            break;
         case XFINALLY:
            Finallys++;
            break;
      XENDX
      return Result;
   }

   ///////////////////////////////////////
   void Bench(int a, int b, int Iterations)
   // benchmark function to call TestFunction in a loop
   // and print timing and statistics 
   {
      DWORD T0, T1;
      int i;

      Calls = Exceptions = Finallys = 0;
      T0 = GetTickCount();
      for (i=0; i<Iterations; i++)
         TestFunction(a, b);
      T1 = GetTickCount();
      printf("%10i %10i %10i %10u\n", Calls, Exceptions, Finallys, T1-T0);
   }

   ///////////////////////////////////////
   int main(void)
   {
      printf("Interation Exceptions Finallys Milliseconds\n"
      "------------------------------------------------\n");
      Bench(1, 1, 1000000); // no exceptions
      Bench(1, 0, 1000000); // raise one exception per loop
      return 0;
   }
   // CPPBENCH.CPP
   // Copyright (c) 1998,99 On Time
   // http://www.on-time.com/
   // Benchmark for C++ Exception Handling

   #include <windows.h>
   #include <stdlib.h>
   #include <stdio.h>

   #define DIVIDE_BY_ZERO -3 // an error code

   // some global variables to count
   // iterations, exceptions, and cleanups

   int Calls, Exceptions, Finallys;

   ///////////////////////////////////////
   int SomeFunction(int a, int b)
   // functiom which can raise an exception
   {
      if (b == 0)
         throw DIVIDE_BY_ZERO;
      return a / b;
   }

   ///////////////////////////////////////
   int TestFunction(int a, int b)
   // test function containing try block
   {
      int Result;

      class Finally {
      public:
         Finally() { Calls++; }
         ~Finally() { Finallys++; }
      } FinallyHandler;

      try
      {
         Result = SomeFunction(a, b);
      }
      catch (int& ErrorCode)
      {
         switch (ErrorCode)
         {
            case DIVIDE_BY_ZERO:
            Exceptions++;
            break;
         default:
            printf("unknown exception!\n");
            throw;
         }
      }
      catch (...)
      {
         printf("non integer exception!\n");
         throw;
      }
      return Result;
   }

   ///////////////////////////////////////
   void Bench(int a, int b, int Iterations)
   // benchmark function to call TestFunction in a loop
   // and print timing and statistics 
   {
      DWORD T0, T1;
      int i;

      Calls = Exceptions = Finallys = 0;
      T0 = GetTickCount();
      for (i=0; i<Iterations; i++)
         TestFunction(a, b);
      T1 = GetTickCount();
      printf("%10i %10i %10i %10u\n", Calls, Exceptions, Finallys, T1-T0);
   }

   ///////////////////////////////////////
   int main(void)
   {
      printf("Interation Exceptions Finallys Milliseconds\n"
      "------------------------------------------------\n");
      Bench(1, 1, 1000000); // no exceptions
      Bench(1, 0, 1000000); // raise one exception per loop
      return 0;
   }

相關推薦

異常/錯誤處理系列C語言如何實現異常處理

前言:     不管是哪門程式語言,在coding過程中,我們都會遇到一個很頭痛的問題,就是如何處理函式的返回值和異常。函式返回值傳統的處理的方法是使用If/else。但對於有返回碼的函式,需要寫“無數”的if分支,程式碼很難看,也不好維護。異常處理更是頭痛,一旦發生,只有

Spring錯誤筆記系列自己new出來的bean中被@Autowired註解修飾的屬性報空指標異常:java.lang.NullPointException

自己new出來的bean中被@Autowired註解修飾的屬性報空指標異常 異常描述 原本我再測試RabbitMQ的傳送程式,裡面用到了一個AmqpTemplate介面,用了@Autowired註解。但是當我使用AmqpTemplate的conver

C學習筆記C語言實現Delphi的Pos()、Copy()、Delete()函式

最近在學習C,深感C指標的強大(和危險),掌握得好,則對記憶體控制如魚得水;掌握不好,輕則得到亂碼,程式異常退出,重則系統藍屏宕機。都說指標是C的靈魂,一點也不為過。 今天拿指標來小試,寫三個字串

SpringBoot錯誤筆記系列SpringBoot工程無法掃描Jar包中的元件(e.g. @Configuration,@Component,etc...)

SpringBoot工程無法掃描Jar包中的元件 背景 這是我在學習SpringSecurity元件時出現的一個問題。大致情況就是 我有兩個工程: security-demo 這是一個springboot工程 security-browser 這是一

演算法C語言實現陣列的動態分配

作者:白寧超 2016年10月27日20:13:13 摘要:資料結構和演算法對於程式設計的意義不言而喻,具有指導意義的。無論從事演算法優化方向研究,還是大資料處理,亦或者網站開發APP開發云云。在求職過程中資料結構必然也是筆試的重點,面試的常客。基於此,系統梳理複習下資料結構和演算法相關知識,其實核心

LinuxC語言實現資料夾拷貝

在《【Linux】利用C語言檔案流複製單一檔案》(點選開啟連結)講述瞭如何用C語言拷貝檔案,但是這隻能拷貝單一檔案。如果你要用LinuxC拷貝整個資料夾,同樣要像《【Java】利用檔案輸入輸出流完成把一個資料夾內的所有檔案拷貝的另一的資料夾的操作》(點選開啟連結)一樣,先用

應用CC語言實現行列式與矩陣的運算系統(+原始碼)

文章目錄 01 - 行列式和矩陣 1.1 - 行列式定義 1.2 - 矩陣定義 02 - 基本運算 2.1 - 行列式基本運算 2.2 - 矩陣基本運算

應用CC語言實現HashSet並模仿Java機制和語法(+原始碼)

文章目錄 01 - HashSet 02 - HashCode 02 - 模仿Java機制和語法 2.1 - 模仿泛型 2.2 - 模仿自動擴容 2.3 - 模仿迭代器 03 - 結果測

C語言C語言實現檔案內容的複製

需求: fgetc   fputc練習 /program檔案下面存在一個檔案 檔名為:addoverflowDemo.c 現在需要在該目錄下複製一個相同的檔案,檔名為test: 程式碼如下: #include <stdio.h> #include <std

杭電100題C語言程式設計練習(三)2014 青年歌手大獎賽_評委會打分

http://acm.hdu.edu.cn/showproblem.php?pid=2014Problem Description青年歌手大獎賽中,評委會給參賽選手打分。選手得分規則為去掉一個最高分和一個最低分,然後計算平均得分,請程式設計輸出某選手的得分。Input輸入資料

杭電100題C語言程式設計練習(四)2022 海選女主角

potato老師雖然很喜歡教書,但是迫於生活壓力,不得不想辦法在業餘時間掙點外快以養家餬口。“做什麼比較掙錢呢?篩沙子沒力氣,看大門又不夠帥...”potato老師很是無奈。“張藝謀比你還難看,現在多有錢呀,聽說還要導演奧運開幕式呢!你為什麼不去娛樂圈發展呢?”lwg在一旁出主意。嗯,也是,為了生存,就委屈點

CCF201709-1打醬油C++程式碼實現

問題描述 小明帶著N元錢去買醬油。醬油10塊錢一瓶,商家進行促銷,每買3瓶送1瓶,或者每買5瓶送2瓶。請問小明最多可以得到多少瓶醬油。 輸入格式 輸入的第一行包含一個整數N,表示小明可用於買醬油的錢數。N是10的整數倍,N不超過300。 輸出格式

HOG特徵提取程式碼(opencv處理基本資料,c語言實現基本演算法)

#include<cv.h> #include<highgui.h> #include<math.h> #include<opencv.hpp> using namespace cv; using namespace std;

厚積薄發系列C++專案總結14—Windows平臺下異常捕獲不到問題分析

問題背景:Windows平臺常用的異常捕獲函式有時候不起作用,特別是XP系統上,有些runtime error捕獲不到,但是其他系統如win7、win8等又能正常捕獲,導致產品發出去後遇到這類異常,莫名其妙的彈一個錯誤框出來導致使用者體驗特別不好。問題解決:windows平臺

C/C++檔案處理系列struct stat 結構體定義

獲取檔案狀態的函式 stat fstat lstat 都與struct stat 有關。函式原型如下,都定義在   sys/stat.h 中,原型如下   int stat(const char *path, struct stat *buf);   int fstat(i

C/C++檔案處理系列fstream::open函式開啟檔案

【fstream::open】 函式原型 void open (const char* filename, ios_base::openmode mode = ios_base::in | ios_base::out); 其中 filename 為

Cc語言裡常見的一些錯誤用法!!!!

1.書寫識別符號時,忽略了大小寫字母的區別。 main() { int a=5; printf("%d",A); } 編譯程式把a和A認為是兩個不同的變數名,而顯示出錯資訊。C認為大寫字母和小寫字母是兩個不同的字元。習慣上,符號常量名用大寫,變數名用小寫表示,以增加可讀性。

編程基礎C語言常見宏定義

ifd 轉換成 erro get 程序 運算 efi 宏定義 當前 我們在使用C語言編寫程序的時候,常常會使用到宏定義以及宏編譯指令,有的可能比較常用,有的可能並不是很常用,是不是所有的C語言宏定義以及宏指令你都清楚呢? 指令 用途詳細介紹 # 空指令,無任何效果 #i

C語言之變量存儲類型

art 技術分享 .net ont alt enter fill img 分享 【精】C語言之變量存儲類型

C語言文件操作詳解

pri void rfi 識別 archive format 隨機 stat 文本文 轉自:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551780.html C語言中沒有輸入輸出語句,所有的輸入輸出功能都用