Cho một tệp nhị phân với các trường nhỏ 32 bit mà tôi cần phân tích cú pháp, tôi muốn viết mã phân tích biên dịch chính xác độc lập với tính cuối của máy thực thi mã đó. Hiện tại tôi sử dụngChuyển đổi tối ưu và di động của endian trong c/C++
uint32_t fromLittleEndian(const char* data){
return uint32_t(data[3]) << (CHAR_BIT*3) |
uint32_t(data[2]) << (CHAR_BIT*2) |
uint32_t(data[1]) << CHAR_BIT |
data[0];
}
điều này, tuy nhiên tạo ra lắp ráp không tối ưu. Trên máy tính của tôi g++ -O3 -S
sản xuất:
_Z16fromLittleEndianPKc:
.LFB4:
.cfi_startproc
movsbl 3(%rdi), %eax
sall $24, %eax
movl %eax, %edx
movsbl 2(%rdi), %eax
sall $16, %eax
orl %edx, %eax
movsbl (%rdi), %edx
orl %edx, %eax
movsbl 1(%rdi), %edx
sall $8, %edx
orl %edx, %eax
ret
.cfi_endproc
lý do tại sao điều này xảy ra? Làm thế nào tôi có thể thuyết phục nó để sản xuất mã tối ưu khi biên soạn trên máy little endian:
_Z17fromLittleEndian2PKc:
.LFB5:
.cfi_startproc
movl (%rdi), %eax
ret
.cfi_endproc
mà tôi đã nhận được bằng cách biên dịch:
uint32_t fromLittleEndian2(const char* data){
return *reinterpret_cast<const uint32_t*>(data);
}
Kể từ khi tôi biết máy của tôi rất ít về cuối nhỏ, tôi biết rằng lắp ráp ở trên là tối ưu, nhưng nó sẽ thất bại nếu biên dịch trên máy tính lớn. Nó cũng vi phạm các quy tắc bí danh nghiêm ngặt, vì vậy nếu được inline, nó có thể tạo ra UB ngay cả trên các máy cuối nhỏ. Có một mã hợp lệ sẽ được biên dịch để tối ưu hóa lắp ráp nếu có thể?
Vì tôi mong đợi chức năng của mình được gạch chân rất nhiều, bất kỳ loại phát hiện cuối kỳ thời gian chạy nào đều không có trong câu hỏi. Cách thay thế duy nhất để viết mã C/C++ tối ưu là sử dụng phát hiện thời gian biên dịch cuối cùng, và sử dụng template
s hoặc #define
s để quay trở lại mã không hiệu quả nếu mục tiêu cuối cùng không phải là nhỏ. Điều này tuy nhiên có vẻ là khá khó khăn để được thực hiện portably.
Bạn không thể khớp 'reinterpret_cast'. Nó không làm bất kỳ sắp xếp lại byte nào. Nếu bạn phải nhảy các byte ngẫu nhiên, bạn phải trả tiền cho ban nhạc. – user4581301
Vấn đề là nếu nền tảng biên dịch mục tiêu của tôi là ít endian thì tôi không cần byte shuffle - trình biên dịch cũng nên biết điều đó, nhưng nó tạo ra mã xáo trộn byte anyway. –
Thing là trình biên dịch không biết bạn đang lật endian. Nó chỉ thấy một loạt các thay đổi và ors. Tuy nhiên, sẽ là một mẹo hay. Có thể chơi ở mức makefile và biên dịch và liên kết trong các chức năng chính xác, nhưng điều đó sẽ giết bất kỳ nội tuyến. – user4581301