停止 printf 打印两次 运行 检查 C 中的框架?
stop printf printing twice running check framework in C?
- 可能对 c 和 c 线程中的打印一般如何发生的深入解释可以解决问题
- 在任何时候都没有使用循环和 scanf
- 因为我的代码使用了检查框架,所以我假设正在进行一些分叉。
- 这很可能与缓冲区有关,所以我使用的是 fflush(stdout),以防万一是因为框架内部的原因,我希望知道框架的人能解释发生了什么。
- 检查框架页面 check.sourceforge.net
- Git link 如果这可能有所帮助 https://github.com/batousik/Practical-C2
- Link 到 build/test 日志,在第 438 行打印开始 https://travis-ci.org/batousik/Practical-C2/builds/53513707
代码示例
START_TEST(test_START_EMPTY_TREE_TREEBASE_PRINT_FREETREE_TEST) {
printf("_________START_EMPTY_TREE/TREEBASE_PRINT/FREETREE_TEST__________\n");
fflush(stdout);
int *ptr;
for (int i = 0; i < arr_size; i++) {
ptr = malloc(sizeof(int));
memcpy(ptr, (int_arr_ptr + i), sizeof(int));
insert(ptr_tree_base_int_1, ptr);
}
// should print tree
printf("!!!Next lines has to be tree printed out\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), true);
printf("_____________________\n");
fflush(stdout);
// No output
ck_assert_int_eq(freeTree(ptr_tree_base_int_1), true);
// should print cannot free empty tree
printf("!!!Next line has to be:\"cannot free empty tree\"\n");
fflush(stdout);
ck_assert_int_eq(freeTree(ptr_tree_base_int_1), true);
// should print cannot print empty tree
printf("!!!Next line has to be:\"cannot print empty tree\"\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), false);
printf("_____________________\n");
fflush(stdout);
ptr_tree_base_int_1 = NULL;
free(ptr_tree_base_int_1);
// should print cannot free empty tree base
printf("!!!Next line has to be:\"cannot free empty tree base\"\n");
fflush(stdout);
ck_assert_int_eq(freeTree(ptr_tree_base_int_1), true);
// should print cannot print empty tree base
printf("!!!Next line has to be:\"cannot print empty tree base\"\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), false);
printf("_____________________\n");
fflush(stdout);
free(int_arr_ptr);
int_arr_ptr = NULL;
printf("freeing the array...\n");
fflush(stdout);
printf("________END_____________\n");
fflush(stdout);
ck_assert_int_eq(ptr_tree_base_int_1->size, 0);
} END_TEST
打印树函数
bool printTree(TreeBase *tree){
void *previous = NULL;
int cnt_tasks = 0;
if (!tree) {
printf("PRINT: Cannot print empty tree base\n");
fflush(stdout);
return false;
}
/* set current to root of binary tree */
TreeNode *current_node = tree->base;
if (!(tree->base)) {
printf("PRINT: Cannot print empty tree\n");
fflush(stdout);
return false;
}
StackNode *stack = NULL;
while (true) {
if(current_node) {
push(&stack, current_node);
current_node = current_node->left;
} else {
if (stack) {
current_node = pop(&stack);
if (cnt_tasks > 1) {
if (tree->comp(previous, current_node->value) != -1) {
printf("PRINTTREE: Invalid BST\n");
fflush(stdout);
assert(NULL);
}
}
previous = current_node->value;
tree->print(current_node->value);
cnt_tasks++;
current_node = current_node->right;
} else {
return (cnt_tasks == tree->size);
}
}
}
}
树->打印函数
void print_ints(void *p){
printf("%d\n", *(int*)p);
fflush(stdout);
}
示例输出
FREETREE: Cant free empty tree
!!!Next line has to be:"cannot free empty tree"
FREETREE: Cant free empty tree
FREETREE: Cant free empty tree
!!!Next line has to be:"cannot print empty tree"
PRINT: Cannot print empty tree
PRINT: Cannot print empty tree
_____________________
代码很多,重点在后面!!!应该有一行但打印两行
printf("PRINT: Cannot print empty tree\n");
fflush(stdout);
return false;
^^ 这一行打印两次
评论:什么是"Macros"?这是来自 API
#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
ck_assert_int_eq
macro introduced in version 0.9.6 of the Check unit testing framework定义为:
#define _ck_assert_int(X, O, Y) ck_assert_msg((X) O (Y), \
"Assertion '"#X#O#Y"' failed: "#X"==%d, "#Y"==%d", X, Y)
#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
可以看出,参数在宏定义中出现了两次:一次用于实际的相等性检查((X) O (Y)
部分),另一次作为 ck_assert_msg(..., X, Y)
的最后一个参数用于失败时记录消息的目的。查看代码的特定部分:
// should print cannot print empty tree
printf("!!!Next line has to be:\"cannot print empty tree\"\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), false);
C 预处理器会相应地将宏扩展为等同于以下代码的代码:
// should print cannot free empty tree
printf("!!!Next line has to be:\"cannot free empty tree\"\n");
fflush(stdout);
ck_assert_msg((printTree(ptr_tree_base_int_1)) == (false),
"Assertion '"#X#O#Y"' failed: "#X"==%d, "#Y"==%d",
printTree(ptr_tree_base_int_1), false);
printTree
函数因此被调用两次并产生所有相关的副作用,包括打印行 "PRINT: Cannot print empty tree"
两次。
保护自己免受此类错误的一种方法是确保宏的参数没有可能的副作用。在您的情况下,这可以通过将调用移至宏外的 printTree
来完成:
bool printTreeResult;
printTreeResult = printTree(ptr_tree_base_int_1);
ck_assert_int_eq(printTreeResult, false);
请注意,由于这种宏通常容易出错(正如您刚刚遇到的那样),因此 ck_assert_int_eq
的定义在 0.9.9 版本中改进为:
#define _ck_assert_int(X, OP, Y) do { \
int _ck_x = (X); \
int _ck_y = (Y); \
ck_assert_msg(_ck_x OP _ck_y, \
"Assertion '"#X#OP#Y"' failed: "#X"==%d, "#Y"==%d", _ck_x, _ck_y); \
} while (0)
#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
相应地,解决重复输出行问题的另一种方法是将 Check 单元测试框架的安装升级到更新的版本(即至少 0.9.9),如果可以的话。
- 可能对 c 和 c 线程中的打印一般如何发生的深入解释可以解决问题
- 在任何时候都没有使用循环和 scanf
- 因为我的代码使用了检查框架,所以我假设正在进行一些分叉。
- 这很可能与缓冲区有关,所以我使用的是 fflush(stdout),以防万一是因为框架内部的原因,我希望知道框架的人能解释发生了什么。
- 检查框架页面 check.sourceforge.net
- Git link 如果这可能有所帮助 https://github.com/batousik/Practical-C2
- Link 到 build/test 日志,在第 438 行打印开始 https://travis-ci.org/batousik/Practical-C2/builds/53513707
代码示例
START_TEST(test_START_EMPTY_TREE_TREEBASE_PRINT_FREETREE_TEST) {
printf("_________START_EMPTY_TREE/TREEBASE_PRINT/FREETREE_TEST__________\n");
fflush(stdout);
int *ptr;
for (int i = 0; i < arr_size; i++) {
ptr = malloc(sizeof(int));
memcpy(ptr, (int_arr_ptr + i), sizeof(int));
insert(ptr_tree_base_int_1, ptr);
}
// should print tree
printf("!!!Next lines has to be tree printed out\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), true);
printf("_____________________\n");
fflush(stdout);
// No output
ck_assert_int_eq(freeTree(ptr_tree_base_int_1), true);
// should print cannot free empty tree
printf("!!!Next line has to be:\"cannot free empty tree\"\n");
fflush(stdout);
ck_assert_int_eq(freeTree(ptr_tree_base_int_1), true);
// should print cannot print empty tree
printf("!!!Next line has to be:\"cannot print empty tree\"\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), false);
printf("_____________________\n");
fflush(stdout);
ptr_tree_base_int_1 = NULL;
free(ptr_tree_base_int_1);
// should print cannot free empty tree base
printf("!!!Next line has to be:\"cannot free empty tree base\"\n");
fflush(stdout);
ck_assert_int_eq(freeTree(ptr_tree_base_int_1), true);
// should print cannot print empty tree base
printf("!!!Next line has to be:\"cannot print empty tree base\"\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), false);
printf("_____________________\n");
fflush(stdout);
free(int_arr_ptr);
int_arr_ptr = NULL;
printf("freeing the array...\n");
fflush(stdout);
printf("________END_____________\n");
fflush(stdout);
ck_assert_int_eq(ptr_tree_base_int_1->size, 0);
} END_TEST
打印树函数
bool printTree(TreeBase *tree){
void *previous = NULL;
int cnt_tasks = 0;
if (!tree) {
printf("PRINT: Cannot print empty tree base\n");
fflush(stdout);
return false;
}
/* set current to root of binary tree */
TreeNode *current_node = tree->base;
if (!(tree->base)) {
printf("PRINT: Cannot print empty tree\n");
fflush(stdout);
return false;
}
StackNode *stack = NULL;
while (true) {
if(current_node) {
push(&stack, current_node);
current_node = current_node->left;
} else {
if (stack) {
current_node = pop(&stack);
if (cnt_tasks > 1) {
if (tree->comp(previous, current_node->value) != -1) {
printf("PRINTTREE: Invalid BST\n");
fflush(stdout);
assert(NULL);
}
}
previous = current_node->value;
tree->print(current_node->value);
cnt_tasks++;
current_node = current_node->right;
} else {
return (cnt_tasks == tree->size);
}
}
}
}
树->打印函数
void print_ints(void *p){
printf("%d\n", *(int*)p);
fflush(stdout);
}
示例输出
FREETREE: Cant free empty tree
!!!Next line has to be:"cannot free empty tree"
FREETREE: Cant free empty tree
FREETREE: Cant free empty tree
!!!Next line has to be:"cannot print empty tree"
PRINT: Cannot print empty tree
PRINT: Cannot print empty tree
_____________________
代码很多,重点在后面!!!应该有一行但打印两行
printf("PRINT: Cannot print empty tree\n");
fflush(stdout);
return false;
^^ 这一行打印两次
评论:什么是"Macros"?这是来自 API
#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
ck_assert_int_eq
macro introduced in version 0.9.6 of the Check unit testing framework定义为:
#define _ck_assert_int(X, O, Y) ck_assert_msg((X) O (Y), \
"Assertion '"#X#O#Y"' failed: "#X"==%d, "#Y"==%d", X, Y)
#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
可以看出,参数在宏定义中出现了两次:一次用于实际的相等性检查((X) O (Y)
部分),另一次作为 ck_assert_msg(..., X, Y)
的最后一个参数用于失败时记录消息的目的。查看代码的特定部分:
// should print cannot print empty tree
printf("!!!Next line has to be:\"cannot print empty tree\"\n");
fflush(stdout);
ck_assert_int_eq(printTree(ptr_tree_base_int_1), false);
C 预处理器会相应地将宏扩展为等同于以下代码的代码:
// should print cannot free empty tree
printf("!!!Next line has to be:\"cannot free empty tree\"\n");
fflush(stdout);
ck_assert_msg((printTree(ptr_tree_base_int_1)) == (false),
"Assertion '"#X#O#Y"' failed: "#X"==%d, "#Y"==%d",
printTree(ptr_tree_base_int_1), false);
printTree
函数因此被调用两次并产生所有相关的副作用,包括打印行 "PRINT: Cannot print empty tree"
两次。
保护自己免受此类错误的一种方法是确保宏的参数没有可能的副作用。在您的情况下,这可以通过将调用移至宏外的 printTree
来完成:
bool printTreeResult;
printTreeResult = printTree(ptr_tree_base_int_1);
ck_assert_int_eq(printTreeResult, false);
请注意,由于这种宏通常容易出错(正如您刚刚遇到的那样),因此 ck_assert_int_eq
的定义在 0.9.9 版本中改进为:
#define _ck_assert_int(X, OP, Y) do { \
int _ck_x = (X); \
int _ck_y = (Y); \
ck_assert_msg(_ck_x OP _ck_y, \
"Assertion '"#X#OP#Y"' failed: "#X"==%d, "#Y"==%d", _ck_x, _ck_y); \
} while (0)
#define ck_assert_int_eq(X, Y) _ck_assert_int(X, ==, Y)
相应地,解决重复输出行问题的另一种方法是将 Check 单元测试框架的安装升级到更新的版本(即至少 0.9.9),如果可以的话。