宏语法引发的错误

时间:2013-10-22 03:06:25

标签: c macros

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

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'。我似乎明白为什么后者有效。

3 个答案:

答案 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)永远不会被评估。

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