我下面的代码和它的一小部分没有意义,因为它超出了我目前的知识,我想知道是否有人可以为我清除这个小问题
stack.h
#ifndef _STACK_H
#define _STACK_H
#include "lis1.h"
typedef List Stack ;
#define stack_init list_init
#define stack_destroy list_destroy
#define stack_size(stack) (stack)->size
#define stack_is_empty(stack) ((stack)->size==0)?1:0
int stack_push(Stack*stack,void*data);
int stack_pop(Stack*stack,void**data);
#endif
请仔细注意#define stack_is_empty(stack) ((stack)->size==0)?1:0
以及编制以下计划时,
#include<stdio.h>
#include"stack.h"
static char ams[5] = { 'h', 'e', 'l', 'l', 'o' };
void* data;
Stack stack;
char*ss;
void debug(int a)
{
printf(" debug %d \n", a);
}
int main()
{
stack_init(&stack, NULL);
debug(1);
int i;
for (i = 0; i < 5; i++)
{
stack_push(&stack, (void*) (&ams[i]));
};
debug(2);
while (printf("checker\n") && stack_is_empty(&stack) != 1)
{
printf("->");
printf("[%d ", stack_size(&stack));
stack_pop(&stack, &data);
printf("%c]", *((char*) data));
printf("--\n");
};
return 0;
}
我明白了
debug 1 debug 2 checker
->[5 o]-- checker
->[4 l]-- checker
->[3 l]-- checker
->[2 e]-- checker
->[1 h]-- checker
segmentation fault
但如果我改变#define stack_is_empty(stack) ((stack)->size==0)?1:0
到#define stack_is_empty(stack) (((stack)->size==0)?1:0)
,没有seg错误
我的查询
我的问题为什么程序在前一种情况下完全正常,直到有条件的喷出'1'。我似乎明白为什么后者有效。
答案 0 :(得分:3)
在C中,宏只是用文本替换,而不考虑它是否产生了你可能期望的表达式。
如果没有括号,您的while
循环条件会扩展为:
printf("checker\n")&&((&stack)->size==0)?1:0!=1
解释为:
(printf("checker\n") && ((&stack)->size==0)) ? 1 : (0 != 1)
printf
因此成为这个三元表达式的条件的一部分,但这不会导致问题,它返回打印的字节数,只要它不为零就会被解释为真。然后根据实际情况执行检查堆栈大小的部分。如果堆栈大小等于零,则返回1或true。如果堆栈大小不等于零,则返回(0 != 1)
的结果,该结果始终为true。所以这个条件总是返回一个真值,而while循环继续运行,即使它已经耗尽了堆栈上的项目。
当你添加括号时,它被解释为你所期望的:
printf("checker\n") && ((((&stack)->size==0)) ? 1 : 0) != 1)
当编写扩展为表达式的宏时,应该总是在结果周围有一对括号,以确保它被解释为单个表达式,而不是运算符优先级规则可能导致表达式的解释与您不同意图。
我应该注意到这个陈述中有很多冗余。您正在检查布尔表达式(&stack)->size==0
的值以查看它是否为真,如果是,则返回1,否则返回0。但如果==
为真,则!= 1
已经返回1,否则返回0;没有三元运算符。然后使用!
查看它是否为假。但是如何从布尔表达式中得到错误?只需使用not运算符!= 1
即可。您可以完全跳过三元运算符和#define stack_is_empty(stack) ((stack)->size==0)
while (!stack_is_empty(&stack)) {
// ...
}
比较:
{{1}}
答案 1 :(得分:2)
请记住,C宏只是文本替换,而不是表达式评估。
使用你的umbra键控stack_is_empty,你的if条件变为:
While (printf("checker\n") && ((&stack)->size)==0)?1:0!=1) {
麻烦的是,!=运算符具有高优先级,因此它实际上变为:
While (printf("checker\n") && ((&stack)->size)==0)?1: (0!=1) ) {
从0!= 1开始,while循环将继续超出堆栈的大小。
答案 2 :(得分:1)
宏替换后
printf("checker\n")&&stack_is_empty(&stack)!=1
变为
printf("checker\n")&&((&stack)->size==0)?1:0!=1
因为三元运算符?:
的优先级相当低,所以相当于:
(printf("checker\n") && ((&stack)->size==0)) ? 1: (0 != 1)
请注意,printf("checker\n")
始终返回一个真值(因为它返回它打印的字符数),因此,由于快捷方式电路,检查(&stack)->size==0)
永远不会被评估。
建议:在宏定义中始终使用足够的括号。