2009-09-11 28 views
7

Như một bài tập, tôi muốn viết một macro cho tôi biết nếu một biến số nguyên được ký. Đây là những gì tôi có cho đến nay và tôi nhận được kết quả tôi mong đợi nếu tôi thử điều này trên một biến char với gcc -fsigned-char hoặc -funsigned-char.Làm cách nào để biết biến số nguyên C có được ký không?

#define ISVARSIGNED(V) (V = -1, (V < 0) ? 1 : 0) 

Đây có phải là thiết bị di động không? Có cách nào để làm điều này mà không phá hủy giá trị của biến?

+0

Đây là một vấn đề tò mò, nhưng tôi càng bị hấp dẫn bởi những gì bạn định sử dụng cho thông tin này Là. Bất kỳ cơ hội chia sẻ? –

+0

Đây là lý do tại sao C++ có RTTI. :) –

+2

@jeffamaphone: Trên thực tế, đây là nơi các mẫu tỏa sáng trong C++. – sbi

Trả lời

4
#define ISVARSIGNED(V) ((V)<0 || (-V)<0 || (V-1)<0) 

không làm thay đổi giá trị của V. Các thử nghiệm thứ ba xử lý các trường hợp V == 0.

Mở trình biên dịch của tôi (gcc/Cygwin) hoạt động này cho intlong nhưng không phải cho char hoặc short.

#define ISVARSIGNED(V) ((V)-1<0 || -(V)-1<0) 

cũng thực hiện công việc trong hai thử nghiệm.

+0

Tốt nhất tôi đã nhìn thấy được nêu ra. Di động, phù hợp tiêu chuẩn, chính xác như xa như tôi có thể nhìn thấy. –

+1

Không phân biệt giữa ký hiệu/unsigned ngắn và char. Các loại đó được quảng bá thành int khi đánh giá biểu thức < == >. – mob

+0

Nếu bạn muốn làm cho nó hoạt động cho 'short' và' char', bạn có thể chuyển biến thành 'char' trước khi sử dụng nó. Điều đó sẽ xử lý hầu hết các vấn đề tràn. Tôi nghĩ rằng ... –

5
#define ISVARSIGNED(V) ((-(V) < 0) != ((V) < 0)) 

Không phá hủy giá trị của biến. Nhưng không hoạt động với 0 giá trị.

gì về:

#define ISVARSIGNED(V) (((V)-(V)-1) < 0) 
+3

#define ISVARSIGNED (V) ((-V <0)! = (V <0)) – plinth

+0

yeah Tôi không nên có C & Pd mà dư thừa công cụ ;-) – ypnos

+0

@plinth, bạn quên "parens" thêm xung quanh 'V' mà làm cho nó an toàn từ mở rộng vĩ mô điên – rmeador

5

Nếu bạn đang sử dụng GCC bạn có thể sử dụng từ khóa typeof để không ghi đè giá trị:

#define ISVARSIGNED(V) ({ typeof (V) _V = -1; _V < 0 ? 1 : 0 }) 

Điều này tạo ra một biến tạm thời, _V, mà có cùng loại với V.

Vì tính di động, tôi không biết. Nó sẽ làm việc trên một máy khen của hai (tất cả mọi thứ mã của bạn sẽ bao giờ chạy trên tất cả các xác suất), và tôi tin rằng nó sẽ làm việc trên khen của một người và máy đăng ký và cường độ là tốt. Lưu ý phụ, nếu bạn sử dụng typeof, bạn có thể muốn truyền -1 đến typeof (V) để làm cho an toàn hơn (tức là ít có khả năng kích hoạt cảnh báo).

+0

Trong C++, nó được đảm bảo hoạt động theo Chuẩn, bất kể biểu diễn số nguyên (đối với n bit, giá trị là 2^n - 1). Tôi không có các tiêu chuẩn C tiện dụng (một trong số họ). –

+0

Tôi không, nhưng tôi nhớ lại đọc trên Wikipedia (nguồn gốc của tất cả những điều đúng: P) rằng tiêu chuẩn C cho phép ba đại diện tôi liệt kê. Không phải bất cứ ai sử dụng chúng nữa ... –

-1

Một đặc điểm phân biệt của phép toán đã ký/chưa ký là khi bạn chuyển đúng số đã ký, bit quan trọng nhất sẽ được sao chép. Khi bạn thay đổi một số không dấu, các bit mới là 0.

#define HIGH_BIT(n) ((n) & (1 << sizeof(n) * CHAR_BITS - 1)) 
#define IS_SIGNED(n) (HIGH_BIT(n) ? HIGH_BIT(n >> 1) != 0 : HIGH_BIT(~n >> 1) != 0 

Vì vậy, về cơ bản, macro này sử dụng biểu thức có điều kiện để xác định xem số bit cao có được đặt hay không. Nếu không, macro sẽ đặt nó bằng cách đảo ngược số bit. Chúng tôi không thể thực hiện phủ định số học vì -0 == 0. Chúng tôi sau đó chuyển ngay bằng 1 bit và kiểm tra xem có mở rộng ký hiệu hay không.

Giả định số học bổ sung 2, nhưng đó thường là giả định an toàn.

+0

Bạn có một nguồn cho những giả định về hành vi của sự thay đổi bit? –

+0

Tiêu chuẩn C99 (phần 6.5.7) cho biết sự dịch chuyển đúng đắn của một giá trị âm, đã ký được thực hiện. Giải thích của tôi là sẽ có phần mở rộng dấu hiệu trên máy bổ sung của 2. Vì C không cụ thể cho các kiến ​​trúc bổ sung của 2 nên chúng sẽ không xuất hiện và nói điều này. –

+0

Bạn sẽ có nhiều PC hơn bằng cách sử dụng 'CHAR_BITS' thay vì phép thuật' 8'. (Vâng, tôi biết, chỉ có rất ít người trong chúng ta _không làm việc trên các máy mà một byte là 8bit. Tuy nhiên.) – sbi

1

Giải pháp đơn giản này không có tác dụng phụ, kể cả lợi ích của việc chỉ đề cập đến v một lần (điều quan trọng trong macro). Chúng tôi sử dụng phần mở rộng gcc "typeof" để có được những loại v, và sau đó đúc -1 đến loại hình này:

#define IS_SIGNED_TYPE(v) ((typeof(v))-1 <= 0) 

Đó là < = thay vì chỉ < để tránh cảnh báo trình biên dịch cho một số trường hợp (khi kích hoạt).

0

Tại sao bạn cần nó làm macro?Mẫu là điều tuyệt vời cho việc này:

template <typename T> 
bool is_signed(T) { 
    static_assert(std::numeric_limits<T>::is_specialized, "Specialize std::numeric_limits<T>"); 
    return std::numeric_limits<T>::is_signed; 
} 

Việc này sẽ hoạt động ngoài mọi loại tích hợp cơ bản. Nó cũng sẽ thất bại tại thời gian biên dịch trên con trỏ, mà phiên bản chỉ sử dụng phép trừ và so sánh có thể sẽ không.

EDIT: Rất tiếc, câu hỏi đòi hỏi C. Tuy nhiên, mẫu là cách thoải mái: P

0

Một cách tiếp cận khác nhau để tất cả các "làm cho nó tiêu cực" câu trả lời:

#define ISVARSIGNED(V) (~(V^V)<0) 

Bằng cách đó không cần phải có trường hợp đặc biệt cho các giá trị khác nhau của V, vì ∀ V ∈ ℤ, V^V = 0.

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