Soru C cinsinden parantez içinde parantez ihtiyacı [duplicate]


Bu sorunun zaten bir cevabı var:

Makro tanımıyla oynamayı denedim SQR aşağıdaki kodda:

#define SQR(x) (x*x)
int main()
{
    int a, b=3;
    a = SQR(b+5);      // Ideally should be replaced with (3+5*5+3), though not sure.
    printf("%d\n",a);
    return 0;
}

Yazdırır 23. Makro tanımını değiştirirseniz SQR(x) ((x)*(x)) daha sonra çıktı beklendiği gibi 64. C dilinde bir makronun çağrısının çağrıyı makro tanımına göre değiştirdiğini biliyorum, ancak hala anlayamıyorum, nasıl hesaplandığını 23.


25
2018-05-30 16:25


Menşei


Gelecekteki kariyerinizde. Makroya güvenmemeye çalışın. Veya bunları kullanmak zorundaysanız, bunları çok küçük kod parçaları için kullanın. Yarım sayfa kaplayan büyük makro canavarlıklar değil. - C Johnson
@CJohnson: Evet, C / C ++ projelerinde bir Makro kullanma ihtiyacını pek fark etmemiştim, bu da yıllardır geliştirici / öğrenci olduktan sonra bile C'nin kafa karıştırıcı alanlarından biri. - Kushal
İlgili: Parantezleri C makro tanımlarında argümanların etrafında çıkarabilir miyiz? - Palec
İlgili: Makrolardaki argümanların etrafındaki parantez ne zaman ihmal edilebilir? - Palec
Bir kopyaya güzel cevap - Palec


Cevaplar:


Önceden çalışan makrolar, kod derlenmeden önce metin değiştirme işlemini gerçekleştirir. SQR(b+5) Çevirir (b + 5 * b + 5) = (6b + 5) = 6 * 3 + 5 = 23

Düzenli işlev çağrıları, işleve iletilmeden önce (b + 3) parametresinin değerini hesaplayacaktır, ancak bir makro önceden derlenmiş bir değiştirme olduğundan, işlemlerin cebirsel sırası çok önemlidir.


27
2018-05-30 16:28





Çünkü (3+5*3+5 == 23).

Buna karşılık ((3+5)*(3+5)) == 64.

Bunu yapmanın en iyi yolu makro kullanmamak:

inline int SQR(int x) { return x*x; }

Ya da sadece yaz x*x.


10
2018-05-30 16:28





Bu makroyu kullanarak makro değiştirmeyi düşünün:

#define SQR(x) (x*x)

kullanma b+5 argüman olarak. Değiştirme işlemini kendiniz yapın. Senin kodunda SQR(b+5) Olacak: (b+5*b+5)veya (3+5*3+5). Şimdi hatırla Operatör Önceliği kurallar: * önce +. Yani bu şöyle değerlendirilir: (3+15+5)veya 23.

Makronun ikinci sürümü:

#define SQR(x) ((x) * (x))

Doğru, çünkü makro argümanlarınızı operatör önceliğinin etkilerinden korumak için parens kullanıyorsunuz.

Bu sayfa C için operatör tercihini açıklamak güzel bir şemaya sahiptir. İşte C11 referans belgesinin ilgili bölümü.

Burada hatırlamanız gereken şey, makrolarınızdaki her türlü argümanı parens kullanarak korumaya alışmanız gerektiğidir.


7
2018-05-30 16:31





Makro genişler

 a = b+5*b+5;

diğer bir deyişle

 a = b + (5*b) + 5;

23 yaşında.


6
2018-05-30 16:27





Makro, yalnızca düz bir metin ikamesidir. Ön işlemden sonra kodunuz şöyle görünür:

int main()
{
    int a, b=3;
    a = b+5*b+5;
    printf("%d\n",a);
    return 0;
}

Çarpma, ekleme işleminden daha yüksek bir operatör önceliğine sahiptir, bu nedenle, değeri hesaplarken iki eklemeden önce yapılır. a. Makro tanımınıza parantez eklemek sorunu oluşturarak sorunu çözer:

int main()
{
    int a, b=3;
    a = (b+5)*(b+5);
    printf("%d\n",a);
    return 0;
}

Parantez içi işlemler çarpımdan önce değerlendirilir, bu yüzden eklemeler önce gerçekleşir ve a = 64 sonuçta beklersiniz.


2
2018-05-30 16:34





Ön işlemden sonra, SQR(b+5) genişletilmiş olacak (b+5*b+5). Bu açıkça doğru değil.

Tanımında iki yaygın hata vardır SQR:

  1. Makro gövdede parantez içinde makro argümanlarını kapsamaz, bu nedenle bu ifadeler ifadeler ise, bu ifadelerde farklı önceliklere sahip operatörler soruna neden olabilir. İşte bu sorunu çözen bir versiyon

    #define SQR(x) ((x)*(x))
    
  2. Makro argümanlarını bir kereden fazla değerlendirmek, bu yüzden bu argümanlar yan etkilere sahip ifadeler ise, bu yan etki bir kereden fazla alınabilir. Örneğin, sonucu düşünün SQR(++x).

    GCC kullanarak bir çeşituzatma, bu sorun böyle düzeltilebilir

    #define SQR(x) ({ typeof (x) _x = (x); _x * _x; })
    

Bu sorunların her ikisi de bu makroyu bir satır içi işleviyle değiştirerek giderilebilir.

   inline int SQR(x) { return x * x; }

Bu, GCC satır içi uzantısı veya C99 gerektirir. 6.40 Bir Satır İçi İşlev, Makro Olarak Daha Hızlıdır.


2
2018-05-27 12:47





Makrolar yalnızca dizge değiştirme olduğundan ve tamamlanma işleminden önce gerçekleştiği için. Derleyici Makro değişkeni ve değerini görme şansına sahip olmayacaktır. Örneğin: Bir makro şöyle tanımlanırsa

#define BAD_SQUARE(x)  x * x 

ve böyle çağırdı

BAD_SQUARE(2+1) 

derleyici bunu görecek

2 + 1 * 2 + 1

hangi, belki beklenmedik sonuç ile sonuçlanacak

5

Bu davranışı düzeltmek için, makro değişkenleri her zaman parantez içine almalısınız.

#define GOOD_SQUARE(x)  (x) * (x) 

bu makro çağrıldığında, örneğin, böyle

GOOD_SQUARE(2+1)

derleyici bunu görecek

(2 + 1) * (2 + 1)

sonuçta

9

Ek olarak, İşte noktayı daha iyi açıklamak için tam bir örnek

#include <stdio.h>

#define BAD_SQUARE(x)  x * x 
// In macros alsways srround the variables with parenthesis
#define GOOD_SQUARE(x)  (x) * (x) 

int main(int argc, char const *argv[])
{
    printf("BAD_SQUARE(2) = : %d \n", BAD_SQUARE(2) ); 
    printf("GOOD_SQUARE(2) = : %d \n", GOOD_SQUARE(2) ); 
    printf("BAD_SQUARE(2+1) = : %d ; because the macro will be \
subsituted as 2 + 1 * 2 + 1 \n", BAD_SQUARE(2+1) ); 
    printf("GOOD_SQUARE(2+1) = : %d ; because the macro will be \
subsituted as (2 + 1) * (2 + 1) \n", GOOD_SQUARE(2+1) ); 

    return 0;
}

0
2018-01-09 20:35