2013-10-22 76 views
0

我下面的代碼和它的一小部分一點也沒有意義,因爲它超出了我的知識有目前,我想知道,如果有人可以清楚這個小問題了,我宏觀語法引起的誤差

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),沒有賽格故障

我的查詢

我的問題,爲什麼做了工作方案前完全正常直到有條件的一個'1'..我似乎明白爲什麼後者的作品。

回答

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)的結果,該結果始終爲真。所以這個條件總是返回一個真正的值,while循環繼續執行,即使在堆棧中的項目用完之後。

當您添加括號,它是如你預期解釋:

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

在編寫擴展到一個表達式宏,你應該始終有一對周圍的結果括號,以確保它被解釋作爲單個表達式,而不是操作符優先規則,可能導致表達式的解釋與您預期的不同。

我應該注意到這個陳述中有很多冗餘。您正在檢查布爾表達式的值(&stack)->size==0以查看它是否爲true,如果是則返回1,否則返回0。但==已經返回1,如果爲真,則返回1;否則返回0;不需要三元操作員。然後,您使用!= 1來查看它是否爲假。但是,如何從布爾表達式中獲得假?只需使用非運算符!即可。您可以跳過三元運算符和完全!= 1比較:

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

while (!stack_is_empty(&stack)) { 
    // ... 
} 
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")總是返回一個真正的值(因爲它返回ns打印多少個字符),因此檢查(&stack)->size==0)永遠不會由於快捷電路而被評估。

建議:總是在宏定義中使用足夠的括號。

2

記住,C宏只是文本替換,而不是表達的評價。

使用您的本影鍵stack_is_empty,你如果條件變爲:

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

麻煩的是,=運算符具有較高的優先級,所以它實際上就變成:!

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

由於0 = 1 ,while循環將繼續超出堆棧的大小。