Tại sao f (i = -1, i = -1) là hành vi không xác định?

269
Nicu Stiurca 2014-02-10 20:31.

Tôi đã đọc về các vi phạm trật tự đánh giá và họ đưa ra một ví dụ khiến tôi khó hiểu.

1) Nếu một hiệu ứng phụ trên một đối tượng vô hướng không được sắp xếp theo trình tự so với một hiệu ứng phụ khác trên cùng một đối tượng vô hướng, thì hành vi là không xác định.

// snip
f(i = -1, i = -1); // undefined behavior

Trong ngữ cảnh này, ilà một đối tượng vô hướng , có nghĩa là

Kiểu số học (3.9.1), kiểu liệt kê, kiểu con trỏ, kiểu con trỏ tới thành viên (3.9.2), std :: nullptr_t và các phiên bản đủ điều kiện cv của những kiểu này (3.9.3) được gọi chung là kiểu vô hướng.

Tôi không thấy làm thế nào tuyên bố là mơ hồ trong trường hợp đó. Đối với tôi, dường như bất kể đối số thứ nhất hay thứ hai được đánh giá trước, ikết thúc là -1, và cả hai đối số cũng vậy -1.

Ai đó có thể vui lòng làm rõ?


CẬP NHẬT

Tôi thực sự đánh giá cao tất cả các cuộc thảo luận. Cho đến nay, tôi thích câu trả lời của @ harmic rất nhiều vì nó cho thấy những cạm bẫy và phức tạp trong việc xác định câu nói này mặc dù thoạt nhìn nó có vẻ đơn giản như thế nào. @ acheong87 chỉ ra một số vấn đề nảy sinh khi sử dụng tài liệu tham khảo, nhưng tôi nghĩ điều đó trực quan với khía cạnh tác dụng phụ chưa được chứng minh của câu hỏi này.


TÓM LƯỢC

Vì câu hỏi này thu hút rất nhiều sự chú ý, tôi sẽ tóm tắt các điểm / câu trả lời chính. Đầu tiên, hãy cho phép tôi lạc đề nhỏ để chỉ ra rằng "tại sao" có thể có những ý nghĩa khác nhau liên quan chặt chẽ nhưng vẫn tinh tế, cụ thể là "vì nguyên nhân gì ", "vì lý do gì " và "vì mục đích gì ". Tôi sẽ nhóm các câu trả lời theo nghĩa nào của "tại sao" mà họ đề cập.

vì nguyên nhân gì

Câu trả lời chính ở đây đến từ Paul Draper , với Martin J đóng góp một câu trả lời tương tự nhưng không bao quát. Câu trả lời của Paul Draper tổng hợp thành

Đó là hành vi không xác định vì nó không được xác định hành vi đó là gì.

Câu trả lời nói chung là rất tốt về mặt giải thích những gì chuẩn C ++ nói. Nó cũng giải quyết một số trường hợp liên quan của UB như f(++i, ++i);f(i=1, i=-1);. Trong trường hợp đầu tiên của các trường hợp liên quan, không rõ liệu đối số đầu tiên nên là đối số i+1thứ hai i+2hay ngược lại; trong phần thứ hai, không rõ inên là 1 hay -1 sau lệnh gọi hàm. Cả hai trường hợp này đều là UB vì chúng thuộc quy tắc sau:

Nếu một hiệu ứng phụ trên một đối tượng vô hướng là không có kết quả so với một tác dụng phụ khác trên cùng một đối tượng vô hướng, thì hành vi đó là không xác định.

Do đó, f(i=-1, i=-1)UB cũng nằm trong quy tắc tương tự, mặc dù ý định của lập trình viên là (IMHO) rõ ràng và không rõ ràng.

Paul Draper cũng nói rõ trong kết luận của mình rằng

Nó có thể đã được xác định hành vi? Đúng. Nó đã được định nghĩa chưa? Không.

điều này đưa chúng ta đến câu hỏi "vì lý do / mục đích gì mà f(i=-1, i=-1)lại bị coi là hành vi không xác định?"

vì lý do / mục đích gì

Mặc dù có một số sơ suất (có thể là do bất cẩn) trong tiêu chuẩn C ++, nhưng nhiều thiếu sót đều có lý do chính đáng và phục vụ một mục đích cụ thể. Mặc dù tôi biết rằng mục đích thường là "làm cho công việc của người biên dịch-người viết dễ dàng hơn", hoặc "viết mã nhanh hơn", tôi chủ yếu quan tâm đến việc liệu có lý do chính đáng để rời khỏi f(i=-1, i=-1) vị trí UB hay không.

harmicsupercat cung cấp các câu trả lời chính cung cấp lý do cho UB. Harmic chỉ ra rằng một trình biên dịch tối ưu hóa có thể chia nhỏ các hoạt động gán nguyên tử bề ngoài thành nhiều lệnh máy và nó có thể xen kẽ thêm các lệnh đó để có tốc độ tối ưu. Điều này có thể dẫn đến một số kết quả rất đáng ngạc nhiên: kết quả ilà -2 trong kịch bản của anh ta! Do đó, tác hại chứng tỏ việc gán cùng một giá trị cho một biến nhiều lần có thể có tác động xấu nếu các phép toán không có câu.

supercat cung cấp một giải thích liên quan về những cạm bẫy của việc cố gắng f(i=-1, i=-1)làm những gì nó trông giống như nó phải làm. Ông chỉ ra rằng trên một số kiến ​​trúc, có những hạn chế khó đối với việc ghi đồng thời nhiều lần vào cùng một địa chỉ bộ nhớ. Một trình biên dịch có thể gặp khó khăn trong việc nắm bắt điều này nếu chúng ta đang xử lý một thứ gì đó ít tầm thường hơn f(i=-1, i=-1).

davidf cũng cung cấp một ví dụ về các hướng dẫn xen kẽ rất giống với của harmic.

Mặc dù mỗi ví dụ của harmic, supercat và davidf 'có phần giống nhau, nhưng kết hợp với nhau, chúng vẫn phục vụ để cung cấp một lý do hữu hình tại sao f(i=-1, i=-1)nên là hành vi không xác định.

Tôi chấp nhận câu trả lời của harmic vì nó đã làm tốt nhất việc giải quyết tất cả các ý nghĩa của lý do tại sao, mặc dù câu trả lời của Paul Draper giải quyết tốt hơn phần "vì nguyên nhân gì".

câu trả lời khác

JohnB chỉ ra rằng nếu chúng ta coi các toán tử gán quá tải (thay vì chỉ là các toán tử vô hướng đơn thuần), thì chúng ta cũng có thể gặp rắc rối.

11 answers

346
harmic 2014-02-10 21:13.

Vì các hoạt động là không có hàng rào, không có gì để nói rằng các lệnh thực hiện nhiệm vụ không thể được xen kẽ. Nó có thể là tối ưu để làm như vậy, tùy thuộc vào kiến ​​trúc CPU. Trang được tham chiếu cho biết điều này:

Nếu A không được giải trình tự trước B và B không được sắp xếp theo trình tự trước A, thì tồn tại hai khả năng:

  • đánh giá A và B là không có câu trả lời: chúng có thể được thực hiện theo bất kỳ thứ tự nào và có thể trùng lặp (trong một luồng thực thi duy nhất, trình biên dịch có thể xen kẽ các lệnh CPU bao gồm A và B)

  • đánh giá A và B được sắp xếp theo trình tự không xác định: chúng có thể được thực hiện theo bất kỳ thứ tự nào nhưng không được trùng lặp: hoặc A sẽ hoàn thành trước B, hoặc B sẽ hoàn thành trước A. Thứ tự có thể ngược lại vào lần sau cùng một biểu thức được đánh giá.

Bản thân điều đó dường như không gây ra sự cố - giả sử rằng thao tác đang được thực hiện đang lưu trữ giá trị -1 vào một vị trí bộ nhớ. Nhưng cũng không có gì để nói rằng trình biên dịch không thể tối ưu hóa điều đó thành một tập hợp các lệnh riêng biệt có cùng tác dụng, nhưng có thể thất bại nếu thao tác này được xen kẽ với thao tác khác trên cùng một vị trí bộ nhớ.

Ví dụ: hãy tưởng tượng rằng việc giảm bộ nhớ bằng 0, sau đó giảm bộ nhớ sẽ hiệu quả hơn so với việc tải giá trị -1 in. Sau đó, điều này:

f(i=-1, i=-1)

có thể trở thành:

clear i
clear i
decr i
decr i

Bây giờ tôi là -2.

Nó có thể là một ví dụ không có thật, nhưng nó hoàn toàn có thể.

209
Paul Draper 2014-02-10 20:39.

Thứ nhất, "đối tượng vô hướng" có nghĩa là một loại giống như một int, floathoặc một con trỏ (xem một đối tượng vô hướng trong C ++ như thế nào? ).


Thứ hai, có vẻ rõ ràng hơn rằng

f(++i, ++i);

sẽ có hành vi không xác định. Nhưng

f(i = -1, i = -1);

là ít rõ ràng hơn.

Một ví dụ hơi khác:

int i;
f(i = 1, i = -1);
std::cout << i << "\n";

Nhiệm vụ nào đã xảy ra "cuối cùng" i = 1, hoặc i = -1? Nó không được định nghĩa trong tiêu chuẩn. Thực sự, điều đó có ithể có 5(xem câu trả lời của harmic để biết lời giải thích hoàn toàn hợp lý cho trường hợp này nên xảy ra như thế nào). Hoặc chương trình của bạn có thể segfault. Hoặc định dạng lại ổ cứng của bạn.

Nhưng bây giờ bạn hỏi: "Còn ví dụ của tôi thì sao? Tôi đã sử dụng cùng một giá trị ( -1) cho cả hai lần gán. Điều gì có thể không rõ ràng về điều đó?"

Bạn đúng ... ngoại trừ cách mà ủy ban tiêu chuẩn C ++ đã mô tả điều này.

Nếu một hiệu ứng phụ trên một đối tượng vô hướng là không có kết quả so với một tác dụng phụ khác trên cùng một đối tượng vô hướng, thì hành vi đó là không xác định.

Họ có thể tạo ra một ngoại lệ đặc biệt cho trường hợp đặc biệt của bạn, nhưng họ đã không. (Và tại sao chúng nên sử dụng? Cái đó sẽ có thể có công dụng gì?) Vì vậy, ivẫn có thể được 5. Hoặc ổ cứng của bạn có thể trống. Vì vậy, câu trả lời cho câu hỏi của bạn là:

Đó là hành vi không xác định vì nó không được xác định hành vi đó là gì.

(Điều này đáng được nhấn mạnh vì nhiều lập trình viên nghĩ rằng "không xác định" có nghĩa là "ngẫu nhiên" hoặc "không thể đoán trước". Nó không phải vậy; nó có nghĩa là không được xác định bởi tiêu chuẩn. Hành vi có thể nhất quán 100% và vẫn không được xác định.)

Nó có thể đã được xác định hành vi? Đúng. Nó đã được định nghĩa chưa? Do đó, nó là "không xác định".

Điều đó nói rằng, "không xác định" không có nghĩa là một trình biên dịch sẽ định dạng ổ cứng của bạn ... nó có nghĩa là nó có thể và nó vẫn sẽ là một trình biên dịch tuân thủ các tiêu chuẩn. Thực tế, tôi chắc chắn rằng g ++, Clang và MSVC đều sẽ làm được những gì bạn mong đợi. Họ sẽ không "phải".


Một câu hỏi khác có thể là Tại sao ủy ban tiêu chuẩn C ++ lại chọn làm cho hiệu ứng phụ này không có kết quả? . Câu trả lời đó sẽ liên quan đến lịch sử và ý kiến ​​của ủy ban. Hoặc Điều gì là tốt khi không có tác dụng phụ này trong C ++? , cho phép bất kỳ lời biện minh nào, cho dù đó có phải là lý do thực tế của ủy ban tiêu chuẩn hay không. Bạn có thể hỏi những câu hỏi đó tại đây hoặc tại programmers.stackexchange.com.

27
Ingo 2014-02-11 00:23.

Một lý do thực tế để không tạo ngoại lệ khỏi các quy tắc chỉ vì hai giá trị giống nhau:

// config.h
#define VALUEA  1

// defaults.h
#define VALUEB  1

// prog.cpp
f(i = VALUEA, i = VALUEB);

Hãy xem xét trường hợp điều này đã được cho phép.

Bây giờ, một vài tháng sau, nhu cầu phát sinh để thay đổi

 #define VALUEB 2

Có vẻ như vô hại phải không? Và đột nhiên prog.cpp không biên dịch nữa. Tuy nhiên, chúng tôi cảm thấy rằng việc biên dịch không nên phụ thuộc vào giá trị của một chữ.

Điểm mấu chốt: không có ngoại lệ đối với quy tắc vì nó sẽ làm cho việc biên dịch thành công phụ thuộc vào giá trị (đúng hơn là kiểu) của một hằng số.

BIÊN TẬP

Tại sao f (i = -1, i = -1) là hành vi không xác định? rằng biểu thức hằng của biểu mẫu A DIV Bkhông được phép trong một số ngôn ngữ, khi Blà 0 và khiến quá trình biên dịch không thành công. Do đó, việc thay đổi một hằng số có thể gây ra lỗi biên dịch ở một số nơi khác. Đó là, IMHO, không may. Nhưng nó chắc chắn là tốt để hạn chế những điều không thể tránh khỏi.

12
davidf 2014-02-12 07:25.

Sự nhầm lẫn là việc lưu trữ một giá trị không đổi vào một biến cục bộ không phải là một lệnh nguyên tử trên mọi kiến ​​trúc mà C được thiết kế để chạy trên đó. Bộ xử lý mã chạy quan trọng hơn trình biên dịch trong trường hợp này. Ví dụ, trên ARM, nơi mỗi lệnh không thể mang hằng số 32 bit hoàn chỉnh, việc lưu trữ một int trong một biến cần nhiều hơn một lệnh đó. Ví dụ với mã giả này, nơi bạn chỉ có thể lưu trữ 8 bit tại một thời điểm và phải hoạt động trong thanh ghi 32 bit, tôi là int32:

reg = 0xFF; // first instruction
reg |= 0xFF00; // second
reg |= 0xFF0000; // third
reg |= 0xFF000000; // fourth
i = reg; // last

Bạn có thể tưởng tượng rằng nếu trình biên dịch muốn tối ưu hóa nó có thể xen kẽ cùng một trình tự hai lần và bạn không biết giá trị nào sẽ được ghi vào i; và hãy nói rằng anh ta không thông minh lắm:

reg = 0xFF;
reg |= 0xFF00;
reg |= 0xFF0000;
reg = 0xFF;
reg |= 0xFF000000;
i = reg; // writes 0xFF0000FF == -16776961
reg |= 0xFF00;
reg |= 0xFF0000;
reg |= 0xFF000000;
i = reg; // writes 0xFFFFFFFF == -1

Tuy nhiên, trong các thử nghiệm của tôi, gcc đủ tốt để nhận ra rằng cùng một giá trị được sử dụng hai lần và tạo ra nó một lần và không có gì kỳ lạ. Tôi nhận được -1, -1 Nhưng ví dụ của tôi vẫn hợp lệ vì điều quan trọng là phải xem xét rằng ngay cả một hằng số có thể không rõ ràng như nó có vẻ.

11
supercat 2014-02-11 06:55.

Hành vi thường được chỉ định là không xác định nếu có một số lý do có thể hình dung được tại sao một trình biên dịch đang cố gắng tỏ ra "hữu ích" có thể làm điều gì đó gây ra hành vi hoàn toàn không mong muốn.

Trong trường hợp một biến được ghi nhiều lần mà không có gì để đảm bảo rằng việc ghi xảy ra vào các thời điểm khác nhau, một số loại phần cứng có thể cho phép thực hiện đồng thời nhiều hoạt động "lưu trữ" đến các địa chỉ khác nhau bằng cách sử dụng bộ nhớ cổng kép. Tuy nhiên, một số bộ nhớ cổng kép rõ ràng cấm trường hợp hai cửa hàng truy cập cùng một địa chỉ đồng thời, bất kể giá trị được ghi có khớp hay không . Nếu một trình biên dịch cho một máy như vậy nhận thấy hai nỗ lực không có hàng rào để viết cùng một biến, nó có thể từ chối biên dịch hoặc đảm bảo rằng hai lần ghi không thể được lên lịch đồng thời. Nhưng nếu một hoặc cả hai truy cập thông qua một con trỏ hoặc tham chiếu, trình biên dịch có thể không phải lúc nào cũng có thể biết liệu cả hai lần ghi có thể đạt đến cùng một vị trí lưu trữ hay không. Trong trường hợp đó, nó có thể lên lịch ghi đồng thời, gây ra bẫy phần cứng khi cố gắng truy cập.

Tất nhiên, thực tế là ai đó có thể triển khai trình biên dịch C trên một nền tảng như vậy không cho thấy rằng hành vi đó không nên được xác định trên nền tảng phần cứng khi sử dụng các cửa hàng thuộc loại đủ nhỏ để được xử lý nguyên tử. Cố gắng lưu trữ hai giá trị khác nhau theo kiểu không có hàng rào có thể gây ra sự kỳ lạ nếu trình biên dịch không biết về nó; ví dụ, đã cho:

uint8_t v;  // Global

void hey(uint8_t *p)
{
  moo(v=5, (*p)=6);
  zoo(v);
  zoo(v);
}

nếu trình biên dịch trong dòng lệnh gọi tới "moo" và có thể thông báo rằng nó không sửa đổi "v", nó có thể lưu trữ từ 5 thành v, sau đó lưu trữ 6 thành * p, sau đó chuyển 5 đến "sở thú" và sau đó chuyển nội dung của v vào "Zoo". Nếu "Zoo" không sửa đổi "v", thì không có chuyện hai lệnh gọi được chuyển các giá trị khác nhau, nhưng dù sao thì điều đó cũng có thể dễ dàng xảy ra. Mặt khác, trong trường hợp cả hai cửa hàng sẽ ghi cùng một giá trị, điều kỳ lạ như vậy không thể xảy ra và trên hầu hết các nền tảng sẽ không có lý do hợp lý để triển khai làm bất cứ điều gì kỳ lạ. Thật không may, một số người viết trình biên dịch không cần bất kỳ lời bào chữa nào cho những hành vi ngớ ngẩn ngoài "vì Tiêu chuẩn cho phép", vì vậy ngay cả những trường hợp đó cũng không an toàn.

9
Amadan 2014-02-10 20:42.

Thực tế là kết quả sẽ là như nhau trong hầu hết các trường trong này trường hợp là ngẫu nhiên; thứ tự đánh giá vẫn chưa được xác định. Hãy xem xét f(i = -1, i = -2): ở đây, vấn đề đặt hàng. Lý do duy nhất khiến nó không quan trọng trong ví dụ của bạn là do cả hai giá trị đều bị lỗi -1.

Cho rằng biểu thức được chỉ định là một biểu thức có hành vi không xác định, trình biên dịch tuân thủ độc hại có thể hiển thị hình ảnh không phù hợp khi bạn đánh giá f(i = -1, i = -1)và hủy bỏ việc thực thi - và vẫn được coi là hoàn toàn chính xác. May mắn thay, không có trình biên dịch nào mà tôi biết làm như vậy.

8
Martin J. 2014-02-10 20:52.

Đối với tôi, có vẻ như quy tắc duy nhất liên quan đến trình tự của biểu thức đối số hàm là ở đây:

3) Khi gọi một hàm (cho dù hàm có nội tuyến hay không và có sử dụng cú pháp gọi hàm rõ ràng hay không), mọi phép tính giá trị và hiệu ứng phụ được kết hợp với bất kỳ biểu thức đối số nào hoặc với biểu thức hậu tố chỉ định hàm được gọi, là trình tự trước khi thực thi mọi biểu thức hoặc câu lệnh trong phần thân của hàm được gọi.

Điều này không xác định trình tự giữa các biểu thức đối số, vì vậy chúng tôi kết thúc trong trường hợp này:

1) Nếu một tác dụng phụ trên một đối tượng vô hướng là không có kết quả so với một tác dụng phụ khác trên cùng một đối tượng vô hướng, thì hành vi là không xác định.

Trong thực tế, trên hầu hết các trình biên dịch, ví dụ bạn đã trích dẫn sẽ chạy tốt (trái ngược với "xóa đĩa cứng của bạn" và các hậu quả hành vi không xác định theo lý thuyết khác).
Tuy nhiên, nó là một trách nhiệm pháp lý, vì nó phụ thuộc vào hành vi của trình biên dịch cụ thể, ngay cả khi hai giá trị được gán giống nhau. Ngoài ra, rõ ràng, nếu bạn cố gắng chỉ định các giá trị khác nhau, kết quả sẽ là "thực sự" không xác định:

void f(int l, int r) {
    return l < -1;
}
auto b = f(i = -1, i = -2);
if (b) {
    formatDisk();
}
8
AlexD 2017-09-13 12:17.

C ++ 17 xác định các quy tắc đánh giá chặt chẽ hơn. Đặc biệt, nó sắp xếp các đối số hàm (mặc dù theo thứ tự không xác định).

N5659 §4.6:15
Đánh giá AB được sắp xếp theo trình tự không xác định khi A được sắp xếp theo trình tự trước B hoặc B được sắp xếp theo trình tự trước A , nhưng không xác định được cái nào. [ Lưu ý : Các đánh giá theo trình tự không xác định không được trùng lặp, nhưng có thể được thực hiện trước. - ghi chú cuối ]

N5659 § 8.2.2:5
Việc khởi tạo một tham số, bao gồm mọi phép tính giá trị liên quan và hiệu ứng phụ, được sắp xếp theo trình tự không xác định đối với bất kỳ tham số nào khác.

Nó cho phép một số trường hợp sẽ là UB trước đây:

f(i = -1, i = -1); // value of i is -1
f(i = -1, i = -2); // value of i is either -1 or -2, but not specified which one
5
JohnB 2014-02-11 04:08.

Toán tử gán có thể bị quá tải, trong trường hợp đó, thứ tự có thể quan trọng:

struct A {
    bool first;
    A () : first (false) {
    }
    const A & operator = (int i) {
        first = !first;
        return * this;
    }
};

void f (A a1, A a2) {
    // ...
}


// ...
A i;
f (i = -1, i = -1);   // the argument evaluated first has ax.first == true
2
Peng Zhang 2014-02-10 20:56.

Đây chỉ là câu trả lời "Tôi không chắc" đối tượng vô hướng "có thể có nghĩa là gì ngoài một cái gì đó như int hoặc float".

Tôi sẽ giải thích "đối tượng vô hướng" là từ viết tắt của "đối tượng kiểu vô hướng", hoặc chỉ "biến kiểu vô hướng". Sau đó, pointer, enum(không đổi) là kiểu vô hướng.

Đây là một bài báo MSDN của Các loại Vô hướng .

2
polkovnikov.ph 2015-04-02 01:03.

Trên thực tế, có lý do để không phụ thuộc vào thực tế là trình biên dịch sẽ kiểm tra igiá trị được gán với cùng một giá trị hai lần, do đó có thể thay thế nó bằng phép gán đơn lẻ. Nếu chúng ta có một số biểu thức thì sao?

void g(int a, int b, int c, int n) {
    int i;
    // hey, compiler has to prove Fermat's theorem now!
    f(i = 1, i = (ipow(a, n) + ipow(b, n) == ipow(c, n)));
}

Related questions

MORE COOL STUFF

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett chia tay chồng sau 3 ngày bên nhau và vẫn kết hôn với anh ấy 25 năm sau

Cate Blanchett đã bất chấp những lời khuyên hẹn hò điển hình khi cô gặp chồng mình.

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Tại sao Michael Sheen là một diễn viên phi lợi nhuận

Michael Sheen là một diễn viên phi lợi nhuận nhưng chính xác thì điều đó có nghĩa là gì?

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Hallmark Star Colin Egglesfield Các món ăn gây xúc động mạnh đối với người hâm mộ tại RomaDrama Live! [Loại trừ]

Ngôi sao của Hallmark Colin Egglesfield chia sẻ về những cuộc gặp gỡ với người hâm mộ ly kỳ tại RomaDrama Live! cộng với chương trình INSPIRE của anh ấy tại đại hội.

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Tại sao bạn không thể phát trực tuyến 'chương trình truyền hình phía Bắc'

Bạn sẽ phải phủi sạch đầu đĩa Blu-ray hoặc DVD để xem tại sao Northern Exposure trở thành một trong những chương trình nổi tiếng nhất của thập niên 90.

Where in the World Are You? Take our GeoGuesser Quiz

Where in the World Are You? Take our GeoGuesser Quiz

The world is a huge place, yet some GeoGuessr players know locations in mere seconds. Are you one of GeoGuessr's gifted elite? Take our quiz to find out!

8 công dụng tuyệt vời của Baking Soda và Giấm

8 công dụng tuyệt vời của Baking Soda và Giấm

Bạn biết đấy, hai sản phẩm này là nguồn điện để làm sạch, riêng chúng. Nhưng cùng với nhau, chúng có một loạt công dụng hoàn toàn khác.

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Hạn hán, biến đổi khí hậu đe dọa tương lai của thủy điện Hoa Kỳ

Thủy điện rất cần thiết cho lưới điện của Hoa Kỳ, nhưng nó chỉ tạo ra năng lượng khi có nước di chuyển. Bao nhiêu nhà máy thủy điện có thể gặp nguy hiểm khi các hồ và sông cạn kiệt?

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Quyên góp tóc của bạn để giúp giữ nước sạch của chúng tôi

Tóc tỉa từ các tiệm và các khoản quyên góp cá nhân có thể được tái sử dụng như những tấm thảm thấm dầu và giúp bảo vệ môi trường.

Tận dụng lợi thế của việc bán hàng nhân Ngày của Cha này

Tận dụng lợi thế của việc bán hàng nhân Ngày của Cha này

Màn hình Samsung Galaxy S9 Plus. Chủ nhật này là Ngày của Cha⁠ — trong trường hợp nó khiến bạn suy nghĩ — và thay vì mua cho anh ấy một chiếc cà vạt trong năm nay, có lẽ đã đến lúc bạn mua cho anh ấy thứ mà anh ấy sẽ thực sự sử dụng.

Assassin's Creed Snuck Into Monster Hunter: World Last Night

Assassin's Creed Snuck Into Monster Hunter: World Last Night

Monster Hunter: World yêu thích các sự kiện chéo. Dù có nghĩa là hóa trang thành Dante của Devil May Cry, giả dạng Horizon: Zero Dawn's Aloy, hay chiến đấu với quái vật Final Fantasy, các nhiệm vụ sự kiện khác nhau của Thế giới được nâng cấp tự do so với các trò chơi khác.

Ava DuVernay Có Quà Tặng Ngày Của Mẹ cho Tất Cả Chúng Ta: Nếp Nhăn Thời Gian Sẽ Được Viết Lại Vào Cuối Tuần Ngày Của Mẹ!

Ava DuVernay Có Quà Tặng Ngày Của Mẹ cho Tất Cả Chúng Ta: Nếp Nhăn Thời Gian Sẽ Được Viết Lại Vào Cuối Tuần Ngày Của Mẹ!

Storm Reid, Oprah Winfrey, Mindy Kaling, Reese Witherspoon và Ava DuVernay tại buổi chiếu đặc biệt của A Wrinkle in Time tại Nhà hát Walter Reade ở Thành phố New York vào ngày 7 tháng 3 năm 2018 “Ava rất mong được nói chuyện với bạn,” một trong những người của Array dư luận viên nói qua điện thoại. (Array là tập thể phân phối, nghệ thuật và vận động chính sách của Ava DuVernay tập trung vào các bộ phim của người da màu và phụ nữ.

Nhiệm vụ bất khả thi 5 sẽ khôi phục niềm tin của bạn trong phim hành động Tentpole

Nhiệm vụ bất khả thi 5 sẽ khôi phục niềm tin của bạn trong phim hành động Tentpole

Mission Impossible: Rogue Nation bắt đầu ở một cấp độ khác. Theo nghĩa đen.

Edwin McCain ra mắt Grand Ole Opry: Quay cảnh hậu trường với nhạc sĩ 'I'll Be'

Edwin McCain ra mắt Grand Ole Opry: Quay cảnh hậu trường với nhạc sĩ 'I'll Be'

McCain, người đang làm việc cho một album mới, lần đầu tiên bước vào vòng kết nối vào tối thứ Sáu ở Nashville

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Forced to Borrow Paris' 'I Love Paris' Sweatshirt After 'Airline Loses All [My] Luggage'

Nicky Hilton Rothschild's luggage got lost, but luckily she has an incredible closet to shop: Sister Paris Hilton's!

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa

Kate Middleton dành một ngày bên bờ nước ở London, cùng với Jennifer Lopez, Julianne Hough và hơn thế nữa. Từ Hollywood đến New York và mọi nơi ở giữa, hãy xem các ngôi sao yêu thích của bạn đang làm gì!

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

17 tuổi bị đâm chết trong khi 4 người khác bị thương trong một cuộc tấn công bằng dao trên sông Wisconsin

Các nhà điều tra đang xem xét liệu nhóm và nghi phạm có biết nhau trước vụ tấn công hay không

Tôi viết như thế nào

Tôi viết như thế nào

Đối với tôi, mọi thứ là về dòng đầu tiên đó và nó sẽ đưa bạn đến đâu. Một số nhà văn bị điều khiển bởi cốt truyện, sự sắp xếp tinh tế của các quân cờ, trong khi những người khác bị lôi cuốn bởi một nhân vật và khả năng thực hiện một cuộc hành trình với một người bạn hư cấu mới.

Đường băng hạ cánh

Đường băng hạ cánh

Cuối hè đầu thu là mùa hoài niệm. Những chiếc đèn đường chiếu ánh sáng của chúng qua những con đường đẫm mưa, và những chiếc lá dưới chân - màu đỏ cam tắt trong bóng chạng vạng - là lời nhắc nhở về những ngày đã qua.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Hãy tưởng tượng tạo ra một chiến lược nội dung thực sự CHUYỂN ĐỔI. Nó có thể.

Vào năm 2021, tôi khuyến khích bạn suy nghĩ lại mọi thứ bạn biết về khách hàng mà bạn phục vụ và những câu chuyện bạn kể cho họ. Lùi lại.

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Sự mất mát của voi ma mút đã mở ra trái tim tôi để yêu

Vào ngày sinh nhật thứ 9 của Felix The Cat, tôi nhớ về một trong những mất mát lớn nhất trong cuộc đời trưởng thành của tôi - Sophie của tôi vào năm 2013. Tôi đã viết bài luận này và chia sẻ nó trên nền tảng này một thời gian ngắn vào năm 2013.

Language