2009-08-18 29 views
7

Tôi có hai quần short 16 bit (s1 và s2) và tôi đang cố kết hợp chúng thành một số nguyên 32 bit (i1). Theo spec tôi đang xử lý, s1 là từ quan trọng nhất, và s2 là từ ít quan trọng nhất, và từ kết hợp dường như được ký. (ví dụ: bit trên cùng của s1 là dấu hiệu.)Cách gọn gàng nhất để kết hợp hai quần short vào một số

Cách sạch nhất để kết hợp s1 và s2 là gì?

tôi đã tìm một cái gì đó giống như

const utils::int32 i1 = ((s1<<16) | (s2)); 

sẽ làm gì, và có vẻ như để làm việc, nhưng tôi lo lắng về trái chuyển một đoạn ngắn bằng 16.

Ngoài ra, tôi quan tâm đến ý tưởng sử dụng một liên minh để thực hiện công việc, bất kỳ suy nghĩ nào về việc đây là một ý tưởng tốt hay xấu?

Trả lời

1

Hãy thử chiếu explicite data.second để loại ngắn, như:

const utils::int32 combineddata = ((data.first<<16) | ((short)data.second)); 

chỉnh sửa: Tôi C# dev, có lẽ là đúc bằng ngôn ngữ mã của bạn trông khác nhau, nhưng ý tưởng có thể là như vậy.

0

Bạn muốn truyền dữ liệu.bắt đầu tới int32 trước khi bạn thực hiện ca, nếu không, ca sẽ tràn bộ nhớ trước khi nó có cơ hội được tự động quảng bá khi được gán cho dữ liệu được kết hợp.

Hãy thử:

const utils::int32 combineddata = (static_cast<utils::int32>(data.first) << 16) | data.second; 

Đây là khóa học giả định rằng data.first và data.second là loại mà có bảo đảm là chính xác 16 bit dài, nếu không bạn có vấn đề lớn hơn.

Tôi thực sự không hiểu tuyên bố của bạn "nếu data.second quá lớn, | sẽ không tính đến thực tế là chúng đều là quần short".

Chỉnh sửa: Và Neil hoàn toàn đúng về sự ký kết.

+5

Trong trường hợp quần short tôi không chắc chắn điều này là cần thiết. Tiêu chuẩn này có: "Các toán hạng phải là loại tích phân hoặc liệt kê và các chương trình khuyến mãi tích phân được thực hiện. Kiểu kết quả là toán hạng của toán hạng trái được khuyến khích". Do đó, đoạn mã ngắn sẽ được quảng bá một cách ngầm định. –

+0

Huh. Tôi không biết điều đó - tôi đoán đó là vì tôi luôn siêu hoang tưởng về kích thước loại dữ liệu. Cảm ơn con trỏ. –

+0

Thật tuyệt khi bị hoang tưởng bởi vì dàn diễn viên chắc chắn sẽ được yêu cầu trên nền tảng với int 16 bit! –

13

Những gì bạn đang làm chỉ có ý nghĩa nếu quần short và int đều không được ký. Nếu một trong hai quần short được ký và có giá trị âm, ý tưởng kết hợp chúng thành một int đơn là vô nghĩa, trừ khi bạn đã được cung cấp một đặc tả miền cụ thể để trang trải một sự kiện như vậy.

+0

Tôi đồng ý rằng mã được đăng có lỗi mở rộng ký hiệu và yêu cầu "kết hợp" hai in16_ts vào int32_t khá kỳ quặc. Nhưng tôi không nghĩ nó nhất thiết là vô nghĩa, theo nghĩa là người ta có thể định nghĩa một số ngữ nghĩa cho hoạt động này. –

+1

Bạn đã đọc 15 từ cuối cùng trong câu trả lời của tôi chưa? –

+0

Vâng, có vẻ như giao diện cho phần cứng đang tách một số nguyên đã ký thành 2 và sau đó gửi nó, bởi vì nó có MSW và LSW, nhưng có vẻ như trong bản ký bổ sung của 2. Vì vậy, tôi cần phải kết hợp lại dữ liệu một cách hợp lý từ đó. – deworde

6

Những gì bạn có vẻ gần đúng, nhưng có thể sẽ thất bại nếu phần thứ hai là số âm; chuyển đổi ngầm thành int có thể sẽ mở rộng và điền 16 bit trên cùng với các bit. Một diễn viên để unsigned ngắn có lẽ sẽ ngăn chặn điều đó xảy ra, nhưng cách tốt nhất để chắc chắn là để che giấu các bit.

const utils::int32 combineddata = ((data.first<<16) | ((data.second) & 0xffff)); 
+0

Tuyệt vời, điều đó có ý nghĩa rất nhiều. – deworde

+0

Thực sự chuyển đổi ngầm thành int sẽ gây ra vấn đề. Ví dụ 'data.first << 16' cũng sẽ gọi hành vi không xác định trong mã được đăng này, nếu data.first là số âm. Vì vậy đây không phải là một giải pháp tốt. Nói chung, nó không phải là một ý tưởng tốt để sử dụng các toán tử shift cùng với các con số đã ký. Giải pháp tốt hơn: 'uint32_t u32 = (uint32_t) data.first << 16 | (uint32_t) dữ liệu.second; combineddate = (int32_t) u32; ' – Lundin

-1

Sử dụng công đoàn để thực hiện công việc giống như lựa chọn tốt, nhưng là vấn đề về tính di động do sự khác biệt về bộ xử lý. Nó có thể thực hiện được, nhưng bạn cần chuẩn bị để sửa đổi công đoàn của mình dựa trên kiến ​​trúc đích. Bit chuyển là xách tay, nhưng xin vui lòng viết một chức năng/phương pháp để làm điều đó cho bạn. Inline nếu bạn thích.

Đối với sự ký kết của quần short, đối với loại hoạt động này, đó là ý nghĩa quan trọng không phải là loại dữ liệu. Nói cách khác, nếu s1 và s2 có nghĩa là để được hiểu là hai nửa của một từ 32 bit, có bit 15 thiết lập chỉ có vấn đề nếu bạn làm một cái gì đó mà có thể gây ra s2 được ký mở rộng.Xem Câu trả lời của Ransoms, có thể tốt hơn là

inline utils::int32 CombineWord16toLong32(utils::int16 s1, utils::int16 s2) 
{ 
    return ((s1 <<16) | (s2 & 0xffff)); 
} 
3

Vì không ai đăng nó, đây là hình thức của công đoàn. Nhưng những nhận xét về endian-ness chắc chắn được áp dụng.

Big-endian:

typedef union { 
    struct { 
     uint16_t high; 
     uint16_t low; 
    } pieces; 
    uint32_t all; 
} splitint_t; 

Little-endian:

typedef union { 
    struct { 
     uint16_t low; 
     uint16_t high; 
    } pieces; 
    uint32_t all; 
} splitint_t; 
+0

lưu ý rằng spec cung cấp zero đảm bảo về điều này. Nó được sử dụng rộng rãi trong C đặc biệt, và tôi nghi ngờ bất kỳ trình biên dịch sẽ cố ý phá vỡ nó, nhưng nó là nghiêm chỉnh nói hành vi không xác định. Bạn không thể viết chung cho một thành viên của một cấu trúc và đọc từ một cấu trúc khác. – jalf

+0

Lưu ý rằng tiêu chuẩn không đảm bảo rằng 'tất cả' sẽ có bất kỳ dữ liệu hợp lý nào sau khi gán cho' cao' và 'thấp' và ngược lại. Giải pháp này không phải là xách tay. – Juliano

+0

Không có lý do gì để sử dụng một liên minh cho điều này, tất cả những gì bạn đạt được là các vấn đề về tính di động. Và loại punning không được xác định rõ trong C++, không giống như C. – Lundin

3

Tôi biết đây là một bài cũ nhưng chất lượng của hiện tại câu trả lời là buồn posted ...

Đây là các vấn đề cần xem xét:

  • Khuyến khích số nguyên tiềm ẩn của quần short (hoặc các loại số nguyên nhỏ khác) sẽ dẫn đến một toán hạng loại int được ký. Điều này sẽ xảy ra bất kể ký hiệu của loại số nguyên nhỏ. Việc thăng tiến số nguyên xảy ra trong các phép toán dịch chuyển và theo bit OR.
  • Trong trường hợp toán tử dịch chuyển, loại kết quả là của toán hạng trái được quảng bá. Trong trường hợp OR bitwise, kiểu kết quả thu được từ "chuyển đổi số học thông thường".
  • Dịch chuyển trái số âm sẽ dẫn đến hành vi không xác định. Việc dịch chuyển đúng một số âm sẽ dẫn đến hành vi được xác định thực hiện (thay đổi logic và số học). Do đó, các số đã ký không nên được sử dụng cùng với các thay đổi bit trong 99% tất cả các trường hợp sử dụng.
  • Công đoàn, mảng và tương tự là giải pháp kém vì chúng làm cho mã phụ thuộc vào endianess. Ngoài ra, gõ punning thông qua các công đoàn cũng không được xác định rõ hành vi trong C++ (không giống như C). Các giải pháp dựa trên con trỏ là không tốt vì chúng sẽ kết thúc vi phạm "quy tắc bí danh nghiêm ngặt".

Một giải pháp thích hợp sẽ do:

  • Sử dụng toán hạng với các loại đó có bảo đảm là unsigned và sẽ không được thăng chức ngầm.
  • Sử dụng dịch chuyển bit vì đây là những thay đổi không phụ thuộc vào endianess.

Nó sẽ giống như thế này:

int32_t i32 = (int32_t)((uint32_t)s1<<16 | (uint32_t)s2); 

Bất kỳ giải pháp khác là rất đáng ngờ và lúc tốt nhất không cầm tay.

+0

Heh. Thành thật mà nói, nhìn lại với 8 năm kinh nghiệm nhiều hơn, những người duy nhất có thể thực sự đã trả lời đây là những nhà thiết kế của API phần cứng. Tôi tự hỏi vào thời điểm đó nếu họ sử dụng một phương pháp kết hợp tiêu chuẩn, nhưng ... – deworde

+0

@deworde Ý của bạn là "API phần cứng"? Mã này gần bằng kim loại như nó được. – Lundin

Các vấn đề liên quan