Trình biên dịch chỉ yêu cầu không thay đổi ý nghĩa của chương trình.
Ý nghĩa của một chương trình được đưa ra bởi ngữ nghĩa của các câu lệnh C của nó, ví dụ: volatile
vòng loại là một cách để tái xác nhận ở cấp độ ngữ nghĩa tương tác với các tác nhân bên ngoài.
volatile
một mình tuy nhiên là vô dụng khi nói đến đồng bộ hóa chủ đề, nó chỉ có hiệu lực cục bộ. Vì vậy, bạn chỉ nên ngụ ý những gì tiêu chuẩn của C ngụ ý, nếu tiêu chuẩn không đưa ra ngữ nghĩa đặt hàng cho một tuyên bố cũng như bất kỳ tác dụng phụ nào, thì không có gì cả.
Để tối ưu hóa một số mã, trình biên dịch phải chứng minh rằng tối ưu hóa không thay đổi ý nghĩa.
Điều này nói chung là một vấn đề khó khăn (hoặc thậm chí không thể giải quyết), do đó, nó được thực hiện chỉ trong bối cảnh đơn giản.
Cân nhắc
#include <stdio.h>
int simple(const int a, const int b)
{
int c = a + b; //3x Memory operation?
int d = c*c; //2x Memory operation?
return d+d; //Memory operation?
}
int main()
{
int a = 0; //Memory operation?
int b = 0; //Memory operation?
a = simple(2, 3); //Function call + Memory operation?
b = simple(3, 4); //Function call + Memory operation?
printf("%d %d\n", a, b); //Function call + 3x Memory operation?
return 0;
}
Tiêu chuẩn C dictates rằng a = simple(2, 3);
được thực hiện trước b = simple(3, 4);
như kết thúc một biểu thức là một điểm chuỗi.
Đây là mã được tạo ra bởi gcc với đầy đủ tối ưu hóa
lea 0x18f0(%rip),%rcx # 0x100403030, "%d %d\n"
mov $0x62,%r8d
mov $0x32,%edx
callq 0x100401110 <printf>
tôi sử dụng Cygwin, vì vậy ABI là một Windows của.Đây là tương đương với
printf("%d %d\n", 50, 98);
Đây là một ví dụ đặc biệt, hàm simple
là tinh khiết và mất thời gian biên dịch thường xuyên biểu, vì vậy kết quả được biết đến tại thời gian biên dịch.
Đây là bằng chứng cho thấy gcc cần thiết để tối ưu hóa các cuộc gọi.
Bằng văn bản khóa mã miễn phí bạn không nên lo lắng về việc tối ưu hóa trình biên dịch ở tất cả miễn là bạn sử dụng ngữ nghĩa chính xác (ví dụ volatile
vì có đọc-ghi truy cập như tác dụng phụ vì lợi ích của tối ưu hóa chỉ).
Điều gì bạn thực sự cần phải lo lắng là memory ordering như được nêu trong nhận xét của tôi.
C11 cuối cùng cũng chứng nhận tất cả điều này trong số memory model.
AFAIK trình biên dịch chỉ yêu cầu không thay đổi ý nghĩa (tức là hành vi quan sát bên ngoài) của chương trình. Là lập trình viên C bạn không thể thực sự kiểm soát các hoạt động bộ nhớ (trình biên dịch có thể bỏ qua hoặc chèn một hoạt động). Ngay cả khi trình biên dịch chỉ phát ra mã như bạn đã viết nó, nó là không sử dụng. Bạn nên đọc [Out Of Order Execution] (https://en.wikipedia.org/wiki/Out-of-order_execution) và [Memory barriers] (https://en.wikipedia.org/wiki/Memory_barrier), cùng với các hướng dẫn tuần tự hóa và nguyên tử để biết thêm thông tin. –
Tiêu chuẩn C cho phép thực hiện một số quyền tự do để thực hiện lại các hoạt động. Tôi không nghĩ rằng có một điều duy nhất được xác định rõ đó là 'chính xác cách tôi viết nó xuống'. Vì vậy, nó sẽ thực thi theo cùng một cách mọi lúc - có (mã được biên dịch định nghĩa một thứ tự thực hiện cố định). Có phải đó chính là cách bạn viết xuống - không xác định. – Persixty
Câu trả lời ngắn gọn: không có gì đảm bảo. –