Hỏi về toán tử 3 ngôi - ternary operation

Nếu bạn đọc đến cuối trang, phần References, bạn sẽ thấy mục ISO/IEC 14882:xxxx, đấy chính là tài liệu chính xác đấy bạn. Và nếu bạn không tìm được thông tin cần thiết trong mấy cái ISO đấy, thì bạn xem mục 6.9.1 sẽ rõ nhé.

Nếu bạn không rõ được code này là UB, hoặc không biết UB là gì thì mình xin phép không thảo luận tiếp về đoạn code này nhé.

Và đây là ý của bạn:

Thì mình khẳng định luôn là ý bạn hoàn toàn sai. 1+2 sẽ không bắt buộc phải tính trước 5^6 trong (1+2)^5^6 với phép ^ là phép lấy mũ.

Phần này thì mình hoàn toàn đồng ý. Nhưng ví dụ này của bạn là về operator precedence của các operator khác nhau, không liên quan gì đến vấn đề kết hợp (associativity) giữa các operator giống nhau (chỉ có ternary operation hoặc chỉ có hàm mũ) như bên trên đã thảo luận. Mình nghĩ comment của bạn @rogp10Hỏi về toán tử 3 ngôi - ternary operation đã cố gắng giải thích cho bạn hiểu rõ vấn đề đang thảo luận là gì để kéo bạn về đúng chủ đề rồi đấy.

Không biết là bạn đọc đoạn này từ đâu, chứ đoạn bên trên rõ ràng là mình chỉ bảo tính 4 trước, chứ không phải 4^5. Mong bạn đọc kỹ lại trước khi thảo luận nhé.

Ví dụ này là ví dụ trực tiếp, đơn giản, dễ hiểu nhất mình có thể nghĩ ra để giải thích link sequence point (đã được đề cập từ May 18, 2020). Nên bản thân mình thì thấy hoàn toàn có liên quan nhé.

Về topic này, mình nghĩ đã giải thích đủ cho chủ topic hiểu. Nên nếu bạn @Cuong_Trinh_Viet còn thắc mắc nào chưa rõ liên quan topic thì mình sẵn lòng giải thích tiếp nhé. Còn thảo luận ngoài lề, có lẽ một topic mới sẽ tốt hơn.

Thân

2 Likes

C++ có hàm mũ đâu mà đi bàn luận hàm mũ thế này thế kia :hocho: :hocho:

bạn kia chắc chưa biết C++ order of evaluation là unspecified rồi https://en.cppreference.com/w/cpp/language/eval_order

trong C++ gọi hàm f(<expression A>, <expression B>) thì chuẩn ko bắt buộc expression A được eval trước hay là expression B được eval trước. Nên có thể có trình dịch eval B rồi A rồi gọi f, có trình dịch eval A rồi B rồi gọi f.

toán tử + cũng là 1 hàm. Viết <expression A> + <expression B> thì trình dịch nó hiểu là gọi hàm operator+(<expression A>, <expression B>). Ví dụ gọi foo() + bar() thì tùy trình dịch mà foo() được gọi trước bar() hay bar() được gọi trước foo(). Thế nên viết (a+b) * (c+d) thì chưa chắc a+b được tính trước hay c+d được tính trước đâu, phải xem trình dịch nó biên dịch ra thế nào nữa :hocho: :hocho:

cái này khác với nhiều ngôn ngữ. Hình như chỉ có C và C++ là ko specified order of evaluation này. Tất cả các ngôn ngữ lập trình khác đều quy định hoặc là trái qua phải hoặc là phải qua trái hết :hocho: :hocho: Trong toán thì thứ tự này ko là vấn đề vì trong toán học ko có biến số, toàn là hằng số :hocho: :hocho: Ví dụ ax^2 + bx + c = 0 giải ra 2 đáp số cũng đặt tên khác nhau là x0 x1, nên trong toán thật ra ko có biến số :hocho: :hocho: Còn trong ngôn ngữ lập trình thì thứ tự tính toán có vấn đề thật, vì 1 hàm có thể có side effect, tức là hàm này thay đổi giá trị biến bên ngoài nó. Ví dụ foo() + bar(), foo sửa biến string s thành hello, bar sửa biến s thành world, cả 2 cùng trả về reference tới s thì nếu foo được eval trước bar kết quả sẽ là worldworld, nhưng nếu bar eval trước thì kết quả lại là hellohello :hocho: :hocho:

đây nha: https://godbolt.org/z/MeW7fr4eE
clang in ra worldworld, g++ in ra hellohello


(ơ clang lẫn g++ ko cần include string mà vẫn chạy tuốt à hoang đường thật :hocho: :hocho:)

ớ mà hình như có thể toy nói sai nữa. Nếu foo và bar cùng modify s thì kết quả foo() + bar() có thể là UB hay sao ấy, nếu như foo xài s += “hi” bar xài s += “hello”: trình dịch có thể tự biên tự diễn interleave các bước trong operator +=: allocate s ra 1 chỗ khác dư 5 chỗ trống cho “hello” trước, rồi sau đó allocate s ra 1 chỗ khác dư 2 chỗ cho “hi”, rồi chép “hello” vào s chỉ có dư 2 chỗ trống này dẫn tới UB :hocho: :hocho: :hocho: :hocho: :hocho:

nói chung ví dụ của toy là hơi xấu xí nhưng cũng đủ để thấy C++ nó ko bắt buộc vế trái tính trước hay vế phải tính trước hay f(a1, a2, a3, a4, …, an) thì ko bắt buộc a1 trước a2 a3 v.v…, có thể nó tính a2 a4 an a1 vẫn được.

3 Likes

Đều là indeterminately sequenced nên không sao.

  1. A function call that is not sequenced before or sequenced after another expression evaluation outside of the function (possibly another function call) is indeterminately sequenced with respect to that evaluation
3 Likes

ok, mình hiểu UB là gì, còn ý mình, UB này được gây ra do cài đặt các cấu trúc dữ liệu, vì vậy việc các cấu trúc dữ liệu được cài đặt là có cơ sở còn về ý phản hồi của bạn, mình xin tiếp nhận để rút kinh nghiệm. Cảm ơn bạn

1 Like
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?