0

我下面的代码和一小部分没有意义,因为它超出了我目前的知识范围,我想知道是否有人可以为我解决这个小问题

堆栈.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)则没有段错误

我的查询

我的问题是为什么程序在前一种情况下工作得非常好,直到条件喷出一个“1”..我似乎理解为什么后者有效。

4

3 回答 3

3

在 C 中,宏只是以文本形式替换,而不考虑它是否产生了您可能期望的表达式。

如果没有括号,您的while循环条件将扩展为:

printf("checker\n")&&((&stack)->size==0)?1:0!=1

这被解释为:

(printf("checker\n") && ((&stack)->size==0)) ? 1 : (0 != 1)

因此printf成为此三元表达式条件的一部分,但这不会导致问题,它返回打印的字节数,只要它不为零,就会被解释为真。然后你根据你的实际情况执行一个检查堆栈大小的部分。如果堆栈大小等于 0,则返回 1 或 true。如果堆栈大小不等于 0,则返回 的结果(0 != 1),该结果始终为真。所以这个条件总是返回一个真值,并且 while 循环继续进行,即使在堆栈上的项目用完之后也是如此。

当您添加括号时,它会按照您的预期进行解释:

printf("checker\n") && ((((&stack)->size==0)) ? 1 : 0) != 1)

在编写扩展为表达式的宏时,您应该始终在结果周围加上一对括号,以确保将其解释为单个表达式,而不是运算符优先规则可能导致表达式的解释与您的预期不同。

我应该注意到,这个声明有很多冗余。您正在检查布尔表达式的值,(&stack)->size==0看它是否为真,如果是则返回 1,否则返回 0。但是==如果它是真的,它已经返回了一个 1,如果不是,它已经返回了一个 0;不需要三元运算符。然后你用!= 1它来看看它是否是假的。但是你如何从布尔表达式中得到错误呢?只需使用 not 运算符,!. 您可以完全跳过三元运算符和!= 1比较:

#define stack_is_empty(stack) ((stack)->size==0)

while (!stack_is_empty(&stack)) {
    // ...
}
于 2013-10-22T03:17:53.853 回答
2

请记住,C 宏只是文本替换,而不是表达式评估。

使用您的本影键控 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 循环将继续超出堆栈的大小。

于 2013-10-22T03:27:44.843 回答
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)由于捷径电路,永远不会评估检查。

建议:在宏定义中始终使用足够的括号。

于 2013-10-22T03:17:41.357 回答