1. 程式人生 > >void相關的無型別變數在使用時必須強制資料型別轉換問題。

void相關的無型別變數在使用時必須強制資料型別轉換問題。



  • const char str[] = "CredO~";
  • unsigned int int32 = 0x80;
  • char ch = '?';
  • void *args[] = {(void*)str,(void*)&int32,(void*)&ch};
  • ...........這裡省略一步將args強制轉換成char * 型的過程...........
  • putnum((unsigned int)*args[1]);/*putnum就是一個輸出值的封裝*/

今晚上我的同學要我看個程式碼,說無法解決,讓我看下。具體問題就在上面的程式碼。
問題描述:int32 = 0x11時,程式碼執行正確,但測試int32 = 0xaa;就是錯誤的,輸出結果很奇怪,在資料前面填充了資料,變成了0xffffffaa。
我拿到程式碼看了好一會,並除錯運行了下,發現確實是這樣的。只要資料最高位為“1”輸出就是錯誤的,也就是和最高位有關係。最高位一般只表示符號位,但現在是無符號變數,這就有點難以理解了。

判斷:由於不存在語法錯誤,指標的使用也沒有問題,那就只能是資料型別的問題了。
嘗試一: 將變數從無符號改為有符號,錯誤依舊,額~~~
嘗試二:在指標取值前先進行強制型別轉換。
  • *(unsigned int *)args[1])

嘗試是正確的,也就是說和指標變數的型別有關,在使用時必須將void * 型指標變數轉換成一個有具體(並且是正確的)資料長度的型別。

雖然解決方法有了,但是原因還不明確,只能反彙編看看了
  • /*原始的方式*/
  • q = *args[1];
  •   401460:   0f be 00      movsx  eaxBYTE PTR [eax]
  • /*              p = *(unsigned int*)args[1];*/
  •                 putnum((unsigned int)q);
  •   401463:   89 04 24                mov    DWORD PTR [esp],eax
  •   401466:   e8 f5 fe ff ff          call   401360 <putnum>
  •   40146b:   e9 70 ff ff ff          jmp    4013e0 <ezprintf+0x10>
  • /*強制轉換後的方式*/
  • /*                q = *args[1];*/
  •               p = *(unsigned int*)args[1];
  •   401460:    8b 00                 mov  eax,DWORD PTR [eax]  
  • E:/C/new  2.c:53
  •                 putnum((unsigned int)p);
  •   401462:    89 04 24                 mov    DWORD PTR [esp],eax
  •   401465:    e8 f6 fe ff ff           call   401360 <putnum>


從加紅的結果很明顯能夠看出,問題在於:沒有進行正確的資料型別轉換,void * 轉換成 char *(正確的轉換型別應該是int *);所以當一開始的資料的最高位為1(單位元組的第7位,例如:b000000001xxxxxxx)時,就被當做符號位進行了符號位擴充套件,出現輸出資料前面被填充的現象(變為:b111111111xxxxxxx)。

結論:void型相關變數在具體使用(和值相關)時必須進行型別強制轉換(並且是要正確的,符合邏輯的),以明確變數的資料長度,否則出現錯誤:
               1、無法編譯通過(資料型別不匹配);
                2、得到錯誤的資料(邏輯上有問題)。


2014.3.23
說明:在原來的帖子中,我說的是由於void * 沒有經行型別強制轉換,編譯器預設為 char *,這是一個很大的錯誤。在這裡指出說明(這個轉換是在其他程式碼中有動作)。出現問題的現象,是由於強制型別轉換的不合理,原變數是int 型,而在使用時資料被轉換成char 型,所以出現錯誤。
新編輯帖子中藍色部分是修正後的,有些錯誤的已經被刪除。這裡特別感謝老九,發現了這個錯誤。


相關推薦

void相關型別變數在使用時必須強制資料型別轉換問題

const char str[] = "CredO~";unsigned int int32 = 0x80;char ch = '?';void *args[] = {(void*)str,(void*)&int32,(void*)&ch};...........這裡省略一步將args強制轉換

hibernate實體類構造方法內含有Timestamp型別變數"Unable to locate approprite constructor"錯誤解決方法

在使用hibernate時,有時想獲取部分欄位的結果集,可以用如下方法: 可以在hql中使用select new 包名.類名(屬性1,屬性2,....)  from 實體類,同時要在實體類中新增帶參的

【Objective-C學習筆記】變數和基本的資料型別

OC是增強了C的特性,所以在變數和基本資料型別上基本與C一致。 在OC中變數命名有如下規則: 由字母、數字、下劃線、$符號組成 必須以字母、下劃線、$符號開頭 大小寫敏感 在OC中定義變數的時候不能使用OC的保留字,OC的保留字如下: OC中有如下基本資料型別: in

Python入門學習:1.變數和簡單的資料型別

python入門學習:1.變數和簡單的資料型別 關鍵點:變數、字串、數字 1.1 變數的命名和使用1.2 字串1.3 數字1.4 註釋 1.1 變數的命名和使用   變數,顧名思義是一個可變的量,每個變數都儲存一個值--與變數關聯的資訊。 1message =

變數,input()方法,註釋,資料型別,if的用法

  一.python是弱型別解釋性語言(沒有強制規定的型別) 1.直譯器種類: CPthon(官方推薦)c語言實現的 PYPY: 把python程式一次性進行編譯 2. idea.lanyus.com  破解JetBrains全家桶 . 二.變數的命名規則   &

變數與常量、資料型別、進位制轉換

資料在記憶體中的儲存方式【瞭解】 儲存資料的單位 在計算機中,最小的操作單位是 位元組 byte 1byte = 8bit 一個位元組對應8個二進位制位 1024byte = 1kb 1024kb = 1mb 1024mb = 1gb 1024gb =

javascript的強制資料型別轉換

強制資料型別轉換主要有三種: 將其它的資料型別轉換為字串 String 將其它的資料型別轉換為數值 Number 將其它的資料型別轉換為布林值 Boolean 1、將其它的資料型別轉換為Str

匿名塊、變數和簡單的資料型別

1.匿名塊的編寫 塊的結構和變數的宣告 declare 變數宣告部分; begin 邏輯處理執行部分; end; / 便於維護(模組化的SQL) 提高資料庫的安全性(把SQL原子操作封裝起來了,更安全) 提高效能(第一次建立物件的時候,資料庫儲存的

Python小白學習之路(八)—【變數】【基本資料型別分類】【集合】【集合的功能】

一、變數 變數的作用:記錄狀態的變化變數的值:描述不同的狀態 二、五大基本資料型別的分類 五大基本資料型別(數字 字串 列表 元祖 字典) 按照可變不可變來進行分類 可變:列表、字典 不可變:字串、數字、元祖 我個人理解,所謂可變,是指當修改內容是,內容改變,地址不變。(即新修改的內容可以覆蓋之

小端模式與強制資料型別轉換

        當運算元的型別不同,而且不屬於基本資料型別時,經常需要強制型別轉換,將運算元轉化為所需要的型別。強制型別轉換具有兩種形式,稱為顯式強制轉換和隱式強制型別轉換。4.1.顯式強制型別轉換         顯式強制型別轉換需要使用強制型別轉換運算子,格式如下:  type(<expressio

萌新向Python資料分析及資料探勘 第一章 Python基礎 第一節 python安裝以及環境搭建 第二節 變數和簡單的資料型別

本文將參考《Python程式設計 從入門到實踐》的講述順序和例子,加上自己的理解,讓大家快速瞭解Python的基礎用法,並將拓展內容的連結新增在相關內容之後,方便大家閱讀。 好了!我們開始第一章的學習。  第一章 Python基礎 第一節 Python安裝以及環境搭建 Python

變數的八種資料型別------06

目錄 一. PHP變數型別-布林型別 二: PHP標量型別-整型 三. PHP標量型別-浮點型 四: PHP標量型別-字串型 五: PHP特殊型別-資源 六: PHP特殊型別-空型別(NULL) 七: 複合型別-陣列 八: 複合型別-物件 一.

強制資料型別轉換

/* 時間:2018.03.06 14:41 目的:1. 強制轉化資料型別 2. 迴圈更新中的變數 i 規範使用中,不能定義為浮點型 */ #include<stdio.h> int main (void) { int i ;

Python基本語法_強制資料型別轉換

目錄 前言 本篇主要介紹Python的強制型別轉換。 軟體環境 系統 UbuntuKylin 14.04 軟體 Python 2.7.3 IPython 4.0.0 Python資料型別的顯式轉換 資料型別的顯示轉換,也稱為

Kotlin學習筆記2 : 變數常量與基本資料型別

一:繼承與類與方法定義: (1)繼承用一個英文冒號: extends---> : 預設的類是不可以被繼承的,只能繼承宣告為open或者abstract的類 open class Person (name: String , surname: String) { } (

C語言全域性變數初始化、資料型別長度

今天在工作中遇到兩個問題,記錄下來: 1. 定義了一個全域性變數,然後初始化,編譯的時候編譯不通過。如下: int a; a = 5; 編譯的時候一直報錯,且說下面的a沒有定義型別,預設類似是int。 後面才發現全域性變數不能再全域性初始化,要初始化則在定義的時候初始化,如

使用CURL斷點續傳遇到的資料型別問題

使用vc2008+CURL開發 HTTP 檔案下載時,發現只要設定了斷點續傳,就無法執行下載,向CURL註冊的下載回撥函式根本就不會被呼叫。 程式碼如下: curl_easy_setopt(curl, CURLOPT_URL, szRemoteUrl); curl_easy

SQL 用於各種資料庫的資料型別(轉載) sqlserver 資料型別 取值範圍 長度

SQL 用於各種資料庫的資料型別 來源 http://www.runoob.com/sql/sql-datatypes.html    面向資料庫程式設計中,資料型別的取值範圍、長度,可能是需要經常檢視的資料。 Microsoft Access、MySQL 和 SQL S

Python資料型別(1)數字資料型別

Python資料型別簡介 Python語言是面向物件的一門程式語言。Python中的資料型別其實就是Python的內建基本物件。內建物件主要包括簡單型別和容器型別。簡單型別主要是數值型資料,容器型別是可以包含其他物件的集體,如序列,元組,對映,集合等。Python中的資料型別也是物件,資料型別像

為什麼泛型類的型別不能是基本資料型別

1.泛型的定義:在程式中我們將一個物件放入集合中,但是集合不會記住物件的型別,當我們在次使用物件的時候,物件變為Object型別,而程式中還是原來的型別,我們必須要自己轉換其型別,為了解決這個問題,則提出泛型。 2.泛型要求包容的是物件型別,而基本資料型別在Java中不屬於物件。但是基本資料型別