(八)cmockery中的calculator和run_tests函數的注釋代碼

? ??所分析的calculator.c和calculator_test.c文件位于 工程中的 cmockery/src/example/ 目錄下,是一個相對而言比較全面的樣例程序,用到了cmockery項目中的大多數單元測試方法。基本上涵蓋了之前所有的樣例程序中的用法,還有兩組測試是database操作的樣例程序沒有做分析也不準備去做了。在結束了這一個樣例程序的分析之后,大概就可以將整個cmockery程序過了百分之70的樣子,接下來就可以將整個項目代碼過一遍了。
calculator.c
  1. #ifdef HAVE_CONFIG_H
  2. #include "config.h"
  3. #endif
  4. #include <assert.h>
  5. #ifdef HAVE_MALLOC_H
  6. #include <malloc.h>
  7. #endif
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <string.h>
  11. #define UNIT_TESTING 1
  12. // If this is being built for a unit test.
  13. #if UNIT_TESTING
  14. /* Redirect printf to a function in the test application so it's possible to
  15. * test the standard output. */
  16. #ifdef printf
  17. #undef printf
  18. #endif // printf
  19. #define printf example_test_printf
  20. extern void print_message(const char *format, ...);
  21. extern int example_test_printf(const char *format, ...);
  22. /* Redirect fprintf to a function in the test application so it's possible to
  23. * test error messages. */
  24. #ifdef fprintf
  25. #undef fprintf
  26. #endif // fprintf
  27. #define fprintf example_test_fprintf
  28. extern int example_test_fprintf(FILE * const file, const char *format, ...);
  29. // Redirect assert to mock_assert() so assertions can be caught by cmockery.
  30. #ifdef assert
  31. #undef assert
  32. #endif // assert
  33. #define assert(expression) \
  34. mock_assert((int)(expression), #expression, __FILE__, __LINE__)
  35. void mock_assert(const int result, const char* expression, const char *file,
  36. const int line);
  37. /* Redirect calloc and free to test_calloc() and test_free() so cmockery can
  38. * check for memory leaks. */
  39. #ifdef calloc
  40. #undef calloc
  41. #endif // calloc
  42. #define calloc(num, size) _test_calloc(num, size, __FILE__, __LINE__)
  43. #ifdef free
  44. #undef free
  45. #endif // free
  46. #define free(ptr) _test_free(ptr, __FILE__, __LINE__)
  47. void* _test_calloc(const size_t number_of_elements, const size_t size,
  48. const char* file, const int line);
  49. void _test_free(void* const ptr, const char* file, const int line);
  50. /* main is defined in the unit test so redefine name of the the main function
  51. * here. */
  52. #define main example_main
  53. /* All functions in this object need to be exposed to the test application,
  54. * so redefine static to nothing. */
  55. #define static
  56. #endif // UNIT_TESTING
  57. // A binary arithmetic integer operation (add, subtract etc.)
  58. typedef int (*BinaryOperator)(int a, int b);
  59. // Structure which maps operator strings to functions.
  60. typedef struct OperatorFunction {
  61. const char* operator;
  62. BinaryOperator function;
  63. } OperatorFunction;
  64. int add(int a, int b);
  65. int subtract(int a, int b);
  66. int multiply(int a, int b);
  67. int divide(int a, int b);
  68. // Associate operator strings to functions.
  69. static OperatorFunction operator_function_map[] = {
  70. {"+", add},
  71. {"-", subtract},
  72. {"*", multiply},
  73. {"/", divide},
  74. };
  75. int add(int a, int b) {
  76. return a + b;
  77. }
  78. int subtract(int a, int b) {
  79. return a - b;
  80. }
  81. int multiply(int a, int b) {
  82. return a * b;
  83. }
  84. int divide(int a, int b) {
  85. assert(b); // Check for divide by zero.
  86. return a / b;
  87. }
  88. /* Searches the specified array of operator_functions for the function
  89. * associated with the specified operator_string. This function returns the
  90. * function associated with operator_string if successful, NULL otherwise.
  91. */
  92. BinaryOperator find_operator_function_by_string(
  93. const size_t number_of_operator_functions,
  94. const OperatorFunction * const operator_functions,
  95. const char* const operator_string) {
  96. size_t i;
  97. assert(!number_of_operator_functions || operator_functions);
  98. assert(operator_string);
  99. for (i = 0; i < number_of_operator_functions; i++) {
  100. const OperatorFunction *const operator_function =
  101. &operator_functions[i];
  102. if (strcmp(operator_function->operator, operator_string) == 0) {
  103. return operator_function->function;
  104. }
  105. }
  106. return NULL;
  107. }
  108. /* Perform a series of binary arithmetic integer operations with no operator
  109. * precedence.
  110. *
  111. * The input expression is specified by arguments which is an array of
  112. * containing number_of_arguments strings. Operators invoked by the expression
  113. * are specified by the array operator_functions containing
  114. * number_of_operator_functions, OperatorFunction structures. The value of
  115. * each binary operation is stored in a pointer returned to intermediate_values
  116. * which is allocated by malloc().
  117. *
  118. * If successful, this function returns the integer result of the operations.
  119. * If an error occurs while performing the operation error_occurred is set to
  120. * 1, the operation is aborted and 0 is returned.
  121. */
  122. int perform_operation(
  123. int number_of_arguments, char *arguments[],
  124. const size_t number_of_operator_functions,
  125. const OperatorFunction * const operator_functions,
  126. int * const number_of_intermediate_values,
  127. int ** const intermediate_values, int * const error_occurred) {
  128. char *end_of_integer;
  129. int value;
  130. unsigned int i;
  131. assert(!number_of_arguments || arguments);
  132. assert(!number_of_operator_functions || operator_functions);
  133. assert(error_occurred);
  134. assert(number_of_intermediate_values);
  135. assert(intermediate_values);
  136. *error_occurred = 0;
  137. *number_of_intermediate_values = 0;
  138. *intermediate_values = NULL;
  139. if (!number_of_arguments)
  140. return 0;
  141. // Parse the first value.
  142. value = (int)strtol(arguments[0], &end_of_integer, 10);
  143. if (end_of_integer == arguments[0]) {
  144. // If an error occurred while parsing the integer.
  145. fprintf(stderr, "Unable to parse integer from argument %s\n",
  146. arguments[0]);
  147. *error_occurred = 1;
  148. return 0;
  149. }
  150. // Allocate an array for the output values.
  151. *intermediate_values = calloc(((number_of_arguments - 1) / 2),
  152. sizeof(**intermediate_values));
  153. i = 1;
  154. while (i < number_of_arguments) {
  155. int other_value;
  156. const char* const operator_string = arguments[i];
  157. const BinaryOperator function = find_operator_function_by_string(
  158. number_of_operator_functions, operator_functions, operator_string);
  159. int * const intermediate_value =
  160. &((*intermediate_values)[*number_of_intermediate_values]);
  161. (*number_of_intermediate_values) ++;
  162. if (!function) {
  163. fprintf(stderr, "Unknown operator %s, argument %d\n",
  164. operator_string, i);
  165. *error_occurred = 1;
  166. break;
  167. }
  168. i ++;
  169. if (i == number_of_arguments) {
  170. fprintf(stderr, "Binary operator %s missing argument\n",
  171. operator_string);
  172. *error_occurred = 1;
  173. break;
  174. }
  175. other_value = (int)strtol(arguments[i], &end_of_integer, 10);
  176. if (end_of_integer == arguments[i]) {
  177. // If an error occurred while parsing the integer.
  178. fprintf(stderr, "Unable to parse integer %s of argument %d\n",
  179. arguments[i], i);
  180. *error_occurred = 1;
  181. break;
  182. }
  183. i ++;
  184. // Perform the operation and store the intermediate value.
  185. *intermediate_value = function(value, other_value);
  186. value = *intermediate_value;
  187. }
  188. if (*error_occurred) {
  189. free(*intermediate_values);
  190. *intermediate_values = NULL;
  191. *number_of_intermediate_values = 0;
  192. return 0;
  193. }
  194. return value;
  195. }
  196. int main(int argc, char *argv[]) {
  197. int return_value;
  198. int number_of_intermediate_values;
  199. int *intermediate_values;
  200. // Peform the operation.
  201. const int result = perform_operation(
  202. argc - 1, &argv[1],
  203. sizeof(operator_function_map) / sizeof(operator_function_map[0]),
  204. operator_function_map, &number_of_intermediate_values,
  205. &intermediate_values, &return_value);
  206. // If no errors occurred display the result.
  207. if (!return_value && argc > 1) {
  208. unsigned int i;
  209. unsigned int intermediate_value_index = 0;
  210. printf("%s\n", argv[1]);
  211. for (i = 2; i < argc; i += 2) {
  212. assert(intermediate_value_index < number_of_intermediate_values);
  213. printf(" %s %s = %d\n", argv[i], argv[i + 1],
  214. intermediate_values[intermediate_value_index++]);
  215. }
  216. printf("= %d\n", result);
  217. }
  218. if (intermediate_values) {
  219. free(intermediate_values);
  220. }
  221. return return_value;
  222. }
這個是calculator.c的源碼,里面自帶了一個main.c程序。這個文件可以直接編譯:gcc calculator.c 然后生成 a.out之后 ?運行就是: ./a.out 1 + 2 - 3 + 4。我在做測試的時候發現不能很好的支持*號。
  1. // A binary arithmetic integer operation (add, subtract etc.)
  2. typedef int (*BinaryOperator)(int a, int b);
  3. // Structure which maps operator strings to functions.
  4. typedef struct OperatorFunction {
  5. const char* operator;
  6. BinaryOperator function;
  7. } OperatorFunction;
  8. int add(int a, int b);
  9. int subtract(int a, int b);
  10. int multiply(int a, int b);
  11. int divide(int a, int b);
  12. // Associate operator strings to functions.
  13. static OperatorFunction operator_function_map[] = {
  14. {"+", add},
  15. {"-", subtract},
  16. {"*", multiply},
  17. {"/", divide},
  18. };
  19. int add(int a, int b) {
  20. return a + b;
  21. }
  22. int subtract(int a, int b) {
  23. return a - b;
  24. }
  25. int multiply(int a, int b) {
  26. return a * b;
  27. }
  28. int divide(int a, int b) {
  29. assert(b); // Check for divide by zero.
  30. return a / b;
  31. }
這樣就構造了一個結構體數組,用來保存運算符號和運算方法的一個映射關系,后續只要在operator_function_map數組里面去根據符號找到執行方法就可以了。

find_operator_function_by_string函數就是執行了上面說的這個功能,根據傳入的操作符號找到對應的函數,并進行返回函數指針。

perform_operation函數中對于傳入的參數進行解析,先解析第一個放到臨時變量value中,然后再循環體重進行解析操作符獲取計算方法的函數指針,然后再獲取另一個操作數,進行執行計算函數,然后返回值會轉儲到value中方便下次繼續使用。肯定有一些錯誤告警日志信息以及錯誤判斷。最終如果參數無誤,將計算的結果進行返回。還有就是在這個函數中會分配一塊內存用來存儲每一次計算得到的中間值信息。

最后的main函數就是調用測試的過程,后續應該把這個main.c該為example_main.c,否則會在calculator_test.c函數編譯的過程中出錯。

關于不能執行乘法的解釋:
? ? 在以./a.out 2 * 3 ?這個命令行進行執行程序的時候,會將其中*號解析為一個通配符,即當前目錄下的所有內容名字的集合。 ?如果想正常調用乘法的話,可以將 * 號用單引號進行包起來就可以正常的調用了。還有就是這個方法只會從左向右進行計算,不會進行優先級的區分(有興趣可以進一步完善喲)。
運行結果如下:

calculator_test.c函數中對于calculator.c函數中的方法進行了單元測試,需要在calculator.c的最開始添加一行 ?#define UNIT_TESTING 1 ?這樣使能單元測試功能。然后執行make:
  1. test : cmockery.c calculator.c calculator_test.c
  2. gcc cmockery.c calculator.c calculator_test.c -g -O0 -o test
  3. clean:
  4. rm -f test

calculator_test.c中的main函數如下:
  1. int main(int argc, char* argv[]) {
  2. UnitTest tests[] = {
  3. unit_test(test_add),
  4. unit_test(test_subtract),
  5. unit_test(test_multiply),
  6. unit_test(test_divide),
  7. unit_test(test_divide_by_zero),
  8. unit_test(test_find_operator_function_by_string_null_functions),
  9. unit_test(test_find_operator_function_by_string_null_string),
  10. unit_test(test_find_operator_function_by_string_valid_null_functions),
  11. unit_test(test_find_operator_function_by_string_not_found),
  12. unit_test(test_find_operator_function_by_string_found),
  13. unit_test(test_perform_operation_null_args),
  14. unit_test(test_perform_operation_null_operator_functions),
  15. unit_test(test_perform_operation_null_number_of_intermediate_values),
  16. unit_test(test_perform_operation_null_intermediate_values),
  17. unit_test(test_perform_operation_no_arguments),
  18. unit_test(test_perform_operation_first_arg_not_integer),
  19. unit_test(test_perform_operation_unknown_operator),
  20. unit_test(test_perform_operation_missing_argument),
  21. unit_test(test_perform_operation_no_integer_after_operator),
  22. unit_test(test_perform_operation),
  23. unit_test(test_example_main_no_args),
  24. unit_test(test_example_main),
  25. };
  26. return run_tests(tests);
  27. }
其中的前四個單元測試就是簡單的一個斷言測試,取test_add為例,如下:
  1. // Ensure add() adds two integers correctly.
  2. void test_add(void **state) {
  3. assert_int_equal(add(3, 3), 6);
  4. assert_int_equal(add(3, -3), 0);
  5. }
test_divide_by_zero,test_find_operator_function_by_string_null_functions,test_find_operator_function_by_string_null_string測試,使用expect_assert_failure,確認100/0是非法的。否則會無法通過測試。

最核心的兩個函數如下,重要的位置都加了注釋。
  1. int _run_test(
  2. const char * const function_name, const UnitTestFunction Function,
  3. void ** const state, const UnitTestFunctionType function_type,
  4. const void* const heap_check_point) {
  5. const ListNode * const check_point = heap_check_point ?
  6. heap_check_point : check_point_allocated_blocks();
  7. void *current_state = NULL;
  8. int rc = 1;
  9. int handle_exceptions = 1;
  10. #ifdef _WIN32
  11. handle_exceptions = !IsDebuggerPresent();
  12. #endif // _WIN32
  13. #if UNIT_TESTING_DEBUG
  14. handle_exceptions = 0;
  15. #endif // UNIT_TESTING_DEBUG
  16. if (handle_exceptions) {
  17. #ifndef _WIN32
  18. unsigned int i;
  19. //注冊新號處理函數,出現異常的時候,會跳到exception_handler這里去處理,
  20. //然后再exception_handler調用longjmp跳回到setjmp位置繼續下一次單元測試。
  21. //會返回并保存默認的信號處理方發指針
  22. for (i = 0; i < ARRAY_LENGTH(exception_signals); i++) {
  23. default_signal_functions[i] = signal(
  24. exception_signals[i], exception_handler);
  25. }
  26. #else // _WIN32
  27. previous_exception_filter = SetUnhandledExceptionFilter(
  28. exception_filter);
  29. #endif // !_WIN32
  30. }
  31. if (function_type == UNIT_TEST_FUNCTION_TYPE_TEST) {
  32. print_message("%s: Starting test\n", function_name);
  33. }
  34. initialize_testing(function_name);
  35. global_running_test = 1;
  36. //在這里進行的setjmp,后續如果出現新號或者錯誤處理,后會返回這里繼續else部分的執行。
  37. if (setjmp(global_run_test_env) == 0) {
  38. Function(state ? state : &current_state);
  39. fail_if_leftover_values(function_name);
  40. /* If this is a setup function then ignore any allocated blocks
  41. * only ensure they're deallocated on tear down. */
  42. if (function_type != UNIT_TEST_FUNCTION_TYPE_SETUP) {
  43. fail_if_blocks_allocated(check_point, function_name);
  44. }
  45. global_running_test = 0;
  46. if (function_type == UNIT_TEST_FUNCTION_TYPE_TEST) {
  47. print_message("%s: Test completed successfully.\n", function_name);
  48. }
  49. rc = 0;
  50. } else {
  51. global_running_test = 0;
  52. print_message("%s: Test failed.\n", function_name);
  53. }
  54. teardown_testing(function_name);
  55. if (handle_exceptions) {
  56. #ifndef _WIN32
  57. unsigned int i;
  58. //在這里回復默認的異常處理函數,每一個單元測試都要這么做一次。
  59. for (i = 0; i < ARRAY_LENGTH(exception_signals); i++) {
  60. signal(exception_signals[i], default_signal_functions[i]);
  61. }
  62. #else // _WIN32
  63. if (previous_exception_filter) {
  64. SetUnhandledExceptionFilter(previous_exception_filter);
  65. previous_exception_filter = NULL;
  66. }
  67. #endif // !_WIN32
  68. }
  69. return rc;
  70. }
  71. int _run_tests(const UnitTest * const tests, const size_t number_of_tests) {
  72. print_message("%d\n",sizeof(int));
  73. // 是否執行下一個測試.
  74. int run_next_test = 1;
  75. // 是否前一個測試執行失敗了.
  76. int previous_test_failed = 0;
  77. //檢查堆指針的狀態
  78. const ListNode * const check_point = check_point_allocated_blocks();
  79. //當前的測試索引
  80. size_t current_test = 0;
  81. //已經執行過測試的個數
  82. size_t tests_executed = 0;
  83. //測試失敗的數目
  84. size_t total_failed = 0;
  85. // setup 函數的個數
  86. size_t setups = 0;//(setup主要實現測試前的初始化工作,teardown主要實現測試完成后的垃圾回收工作)
  87. // teardown 函數的個數
  88. size_t teardowns = 0;
  89. /* 一個測試狀態的棧. 一個狀態是當測試的setup發生時入棧
  90. * 另個是當測試的teardown發生時出棧 */
  91. TestState* test_states = malloc(number_of_tests * sizeof(*test_states));
  92. size_t number_of_test_states = 0;
  93. //失敗測試的名字指針數組,最多為所有的都失敗
  94. const char** failed_names = malloc(number_of_tests *
  95. sizeof(*failed_names));
  96. void **current_state = NULL;
  97. //確保最大的整數類型要不小于一個指針類型
  98. assert_true(sizeof(LargestIntegralType) >= sizeof(void*));
  99. while (current_test < number_of_tests)
  100. {
  101. const ListNode *test_check_point = NULL;
  102. TestState *current_TestState;
  103. const UnitTest * const test = &tests[current_test++];
  104. if (!test->function)
  105. {//如果結構體中的函數指針為空,那么就continue
  106. continue;
  107. }
  108. //以run_next_test控制是否為test,區分setup必須首先被執行。
  109. switch (test->function_type)
  110. {
  111. case UNIT_TEST_FUNCTION_TYPE_TEST:
  112. run_next_test = 1;
  113. break;
  114. case UNIT_TEST_FUNCTION_TYPE_SETUP:
  115. {
  116. // Checkpoint the heap before the setup.
  117. current_TestState = &test_states[number_of_test_states++];
  118. current_TestState->check_point = check_point_allocated_blocks();
  119. test_check_point = current_TestState->check_point;
  120. current_state = &current_TestState->state;
  121. *current_state = NULL;
  122. run_next_test = 1;
  123. setups ++;
  124. break;
  125. }
  126. case UNIT_TEST_FUNCTION_TYPE_TEARDOWN:
  127. // Check the heap based on the last setup checkpoint.
  128. assert_true(number_of_test_states);
  129. current_TestState = &test_states[--number_of_test_states];
  130. test_check_point = current_TestState->check_point;
  131. current_state = &current_TestState->state;
  132. teardowns ++;
  133. break;
  134. default:
  135. print_error("Invalid unit test function type %d\n",
  136. test->function_type);
  137. exit_test(1);
  138. break;
  139. }
  140. if (run_next_test)
  141. {//進入測試單元進行運行函數
  142. int failed = _run_test(test->name, test->function, current_state,
  143. test->function_type, test_check_point);
  144. if (failed)
  145. {//記錄錯誤函數的名字,后續會用來記錄輸出
  146. failed_names[total_failed] = test->name;
  147. }
  148. switch (test->function_type)
  149. {//統計信息
  150. case UNIT_TEST_FUNCTION_TYPE_TEST:
  151. previous_test_failed = failed;
  152. total_failed += failed;
  153. tests_executed ++;
  154. break;
  155. case UNIT_TEST_FUNCTION_TYPE_SETUP:
  156. if (failed)
  157. {
  158. total_failed ++;
  159. tests_executed ++;
  160. // Skip forward until the next test or setup function.
  161. run_next_test = 0;
  162. }
  163. previous_test_failed = 0;
  164. break;
  165. case UNIT_TEST_FUNCTION_TYPE_TEARDOWN:
  166. // If this test failed.
  167. if (failed && !previous_test_failed)
  168. {
  169. total_failed ++;
  170. }
  171. break;
  172. default:
  173. assert_false("BUG: shouldn't be here!");
  174. break;
  175. }
  176. }
  177. }
  178. //輸出打印信息,并且釋放申請的資源
  179. if (total_failed)
  180. {
  181. size_t i;
  182. print_error("%d out of %d tests failed!\n", total_failed,
  183. tests_executed);
  184. for (i = 0; i < total_failed; i++)
  185. {
  186. print_error(" %s\n", failed_names[i]);
  187. }
  188. }
  189. else
  190. {
  191. print_message("All %d tests passed\n", tests_executed);
  192. }
  193. if (number_of_test_states)
  194. {
  195. print_error("Mismatched number of setup %d and teardown %d "
  196. "functions\n", setups, teardowns);
  197. total_failed = -1;
  198. }
  199. free(test_states);
  200. free((void*)failed_names);
  201. //如果在這里還沒有回復堆區域,那么就說明內存存在泄漏
  202. fail_if_blocks_allocated(check_point, "run_tests");
  203. return (int)total_failed;
  204. }
后續這個測試框架可以以靜態庫的方式存在于項目中,單獨的簡歷一個測試文件夾,專門用于各個模塊的單元測試代碼。或者就編譯成動態庫安裝到系統里,都是可以的。










轉載于:https://www.cnblogs.com/cfzhang/p/a1d8bd91d72fbe49bd015471b049f2bb.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/371391.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/371391.shtml
英文地址,請注明出處:http://en.pswp.cn/news/371391.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

家用雙wan口路由器推薦_請推薦雙WAN口的有線千兆硬路由器?

利益相關&#xff1a;TP-LINK一線銷售人員(來看看會不會有推薦我司產品的2333 )路由器&#xff1a;TL-ER3220G&#xff0c;帶機量300終端&#xff0c;可管理50個AP&#xff0c;最大支持四條寬帶接入POE交換機&#xff1a;TL-SF1005P(5口百兆) TL-SG1005P(5口千兆) TL-SF1009PH(…

第一章魔獸窗口

開始顯示第一個窗體 用戶直接點登陸的話就會提示用戶名不能為空密碼不能為空 沒有賬號的話只能先注冊&#xff0c;點擊藍色摁鈕進入下一個窗體 這里有判斷是否為空&#xff0c;注冊成功后利用窗體傳值&#xff0c;并且打開第一個窗口 把注冊的用戶名和密碼寫上去就可以的登陸到…

Apache Digester示例–輕松配置

解決問題–硬編碼&#xff0c;需要為您的應用程序創建自定義配置&#xff0c;例如struts配置文件&#xff0c;以僅通過更改文件來改變應用程序行為。 Apache Digester可以輕松為您完成此任務。 使用Apache Digester相當容易將XML文檔轉換為相應的Java bean對象層次結構。 請參閱…

騰訊云搭svn服務器,騰訊云使用筆記二: 安裝svn服務器及web同步

A01&#xff1a;安裝subversionsudo apt-get install subversionA02:創建倉庫很多目錄可以放subversion文件倉庫&#xff0c;最常見的是/usr/local/svn和/home/svnsudo mkdir -p /home/svn/youshengyousesudo svnadmin create /home/svn/youshengyouse//說明&#xff1a;先創建…

python將圖像轉換為8位單通道_使用Python將圖片轉換為單通道黑白圖片

本文介紹如何使用python將圖片轉換為純黑白的單通道圖片。文中用到的腳本支持彩色、灰度、帶alpha通道的輸入圖片以及SVG矢量圖&#xff0c;支持調整輸出圖片大小以及設置灰度閾值。最后介紹如何輸出SSD1306 OLED顯示屏可用的XBM文件&#xff0c;并利用輸出的XBM數據在0.96寸的…

Java FlameGraph 火焰圖

上周一個偶然的機會聽同事提到了Java FlameGraph&#xff0c;剛實驗了一下&#xff0c;效果非常好。 一、什么是FlameGraph 直接看圖說話。FlameGraph 是 SVG格式&#xff0c;矢量圖&#xff0c;可以隨意擴大縮小&#xff0c;看不清的信息可以放大看。圖中&#xff0c;各種紅橙…

ADB 常用命令

獲取Android設備號 adb shell getprop ro.serialno 獲取系統版本 adb shell getprop ro.build.version.release>4.2.2 獲取系統api版本 adb shell getprop ro.build.version.sdk>17 獲取設備分辨率&#xff08;SDK4.3&#xff09; adb shell wm size獲取設備屏幕密度&am…

哪個Java線程消耗了我的CPU?

當您的Java應用程序占用100&#xff05;的CPU時&#xff0c;您該怎么辦&#xff1f; 事實證明&#xff0c;您可以使用內置的UNIX和JDK工具輕松找到有問題的線程。 不需要探查器或代理。 為了進行測試&#xff0c;我們將使用以下簡單程序&#xff1a; public class Main {publi…

煙草局計算機筆試,2020年廣西南寧煙草局什么時候筆試?

最近廣西煙草局各地市社招通知頻發&#xff0c;南寧煙草局報名截止至今都無任何消息&#xff0c;根據往年的考情&#xff0c;通知近期很大可能會發布&#xff0c;將于6月底完成筆面!你備考好了嗎&#xff1f;今天廣西中公國企小編來給大家說一下南寧煙草局社招的筆試內容及備考…

JAVA Swing 組件演示***

下面是Swing組件的演示&#xff1a; package a_swing;import java.awt.BorderLayout; import java.awt.Color; import java.awt.Container; import java.awt.Cursor; import java.awt.Dimension; import java.awt.GridLayout; import java.awt.event.ActionEvent; import java.…

Spring 3.1緩存和@CacheEvict

我的上一個博客演示了Spring 3.1的Cacheable批注的應用&#xff0c; Cacheable批注用于標記返回值將存儲在緩存中的方法。 但是&#xff0c; Cacheable只是Spring的Guy為緩存而設計的一對注釋??中的一個&#xff0c;另一個是CacheEvict 。 像Cacheable一樣&#xff0c; Cache…

centos 獲取硬件序列號_如何在 Linux 上查找硬件規格

在 Linux 系統上有許多工具可用于查找硬件規格。-- Sk&#xff08;作者&#xff09;在 Linux 系統上有許多工具可用于查找硬件規格。在這里&#xff0c;我列出了四種最常用的工具&#xff0c;可以獲取 Linux 系統的幾乎所有硬件&#xff08;和軟件&#xff09;細節。好在是這些…

位置服務器管理器,查看 DIMM 位置

鍵入&#xff1a;-> show /System/Memory/DIMMs -t locationTarget | Property | Value-----------------------------------------------------------------------/System/Memory/DIMMs/ | location | CMIOU0/CM/CMP/BOB00/CH0/DIMM (CPU MemoryDIMM_0 | | IO Unit 0 Memor…

Spring –持久層–編寫實體并配置Hibernate

歡迎來到本教程的第二部分。 當您看到本文有多長時間時&#xff0c;請不要驚慌–我向您保證&#xff0c;這主要是簡單的POJO和一些生成的代碼。 在開始之前&#xff0c;我們需要更新我們的Maven依賴項&#xff0c;因為我們現在將使用Hibernate和Spring。 將以下依賴項添加到pom…

無線服務器主機名是,wifi默認服務器主機名

wifi默認服務器主機名 內容精選換一換以CentOS 7操作系統的彈性云服務器為例&#xff1a;登錄Linux彈性云服務器&#xff0c;查看“cloud-init”的配置文件。檢查“/etc/cloud/cloud.cfg”文件中“update_hostname”是否被注釋或者刪除。如果沒有被注釋或者刪除&#xff0c;則需…

pygame里面物體閃爍運動_利用自閃爍發光二極管探究小車在傾斜軌道上的運動規律...

2020年11月23日&#xff0c;周一&#xff0c;24小時安全值班。利用當班中午的時間&#xff0c;微主在創客空間測試了自閃爍發光二極管在勻加速運動中的效果&#xff0c;結果還比較滿意。將小車放置在傾斜的軌道上&#xff0c;將自閃爍發光二極管和紐扣電池構成頻閃光源&#xf…

python網絡爬蟲與信息提取 學習筆記day3

Day3&#xff1a; 只需兩行代碼解析html或xml信息 具體代碼實現:day3_1 注意BeautifulSoup的B和S需要大寫&#xff0c;因為python大小寫敏感 import requests r requests.get("http://python123.io/ws/demo.html") r.text demo r.text from bs4 import Beauti…

番石榴文件:Java文件管理

正如我在這里 &#xff0c; 這里 &#xff0c; 這里和這里所討論的那樣&#xff0c; Groovy和Java SE 7都為Java文件管理提供了改進。 但是&#xff0c;當特定的Java應用程序尚不能使用Java SE 7或Groovy進行文件管理時&#xff0c;仍然可以通過使用Guava的Files類獲得改進的文…

順序查找

順序查找屬于查找中較容易的一個方法&#xff0c;且對數據是否已經排序沒有要求&#xff0c;是很常用的一個查找算法。 但缺點是必須一個一個數字進行比較查找&#xff0c;查找所需步驟可能較多。 順序查找算法的思想是&#xff0c;將目標與待查找數據進行比較&#xff0c;若發…

王者榮耀微信哪個服務器人最少,王者榮耀:微信區王者人數銳減,大神們都去哪了?這些原因很真實...

原標題&#xff1a;王者榮耀&#xff1a;微信區王者人數銳減&#xff0c;大神們都去哪了&#xff1f;這些原因很真實王者榮耀&#xff1a;微信區王者人數銳減&#xff0c;大神們都去哪了&#xff1f;這些原因很真實大家好&#xff01;王者榮耀S16賽季已經開啟一月之余&#xff…