當前位置:
首頁 > 知識 > C語言——老江湖不容忽視的新問題你有遇到嗎?

C語言——老江湖不容忽視的新問題你有遇到嗎?


C語言代碼碰到的問題,都是些小問題,但是,越是小問題,越是不好解決,希望對大家有所幫助.


有句話說的好,你有一個思想,我有一個思想,大家交流一下,就是兩個思想,共同進步吧.


// test.cpp : Defines the entry point for the console application.


//


#include "stdafx.h"

// 編寫代碼的幾類問題


// 1 fscanf


// 2 文件操作


// 3 變數邊界


// 4 編譯順序


// 5 計算精度


// 6 邊界對齊


// 7 指針與逗號語句


// 8 指針應用


// 9 死循環

// 10 文件系統


// 11 改變演算法流程


// 12 改變演算法模型


想要一起學習C 的可以加裙二四八八九四四三零,有很多大神一起學習交流,有資源,然後可以訂閱一下


/*


// ================== fscanf() ==================


// test.txt : 1 2 3 4 5 6 7 8 9 0 1 2


int main( int argc , char* argv[ ] )


{


FILE *f ;

char buf[ 11] ;


int i ;


if( ( f = fopen( "test.txt" , "r" ) ) == NULL )


{


printf( "Can"t Open The File" ) ;


return 0 ;


}


for( i = 0 ; i


{


//fscanf( f , "%x" , &buf[ i ] ) ; // A

fscanf( f , "%x" , &buf[ 9-i ] ) ; // B


}


fclose( f ) ;


printf( "
End : " ) ;


for( i = 0 ; i


{


printf( "%02x " , buf[ i ] ) ;


}


printf( "
" ) ;


return 0;

}*/


/*


這段代碼完成的工作就是將文件中的十個數字,從9-0反序放到數組buf中,但是,在實際執行過程中,有下面兩個問題


1. 會產生溢出錯誤....,A,B均有


2. 在B方式下,輸出結果全0


這個問題實在是有點讓人莫名其妙的


給大家一個分析這個問題的辦法,在//B方案下面添加如下代碼:


printf( "
NO.%d : " , i ) ;


for( int j = 0 ; j


{

printf( "%02x " , buf[ j ] ) ;


}


分析:


1. fcanf("%x")做為一個(四位元組)整型X讀入,然後強制&0xff( char),然後,按照intel數據順序,低位在前,高位在後,寫四個位元組,在A,B方式下,問題1均是由於對buf[9]的賦值產生的邊界溢出造成的,buf的緩衝區長度最少應為13.......OMG


2 .在B方式下,由於一次對四個位元組賦值,從數組尾向前的運動方式,使的數組從後向前逐個賦0!!


解決辦法


1 int buf[10 ];


2 char a;


fscanf(f,"%x",&a);


buf[9-i]=a&0xff;

寫這個例子只是想告訴大家,其實很多時候,代碼本身是沒錯的,錯在系統,大家要學代碼設計,一定要記住,任何代碼都是在一定的環境下實現的,要想寫好代碼,一定要對代碼的應用環境有充分的認識。


*/


/*


// ================== 文件操作 ==================


unsigned char pool[ 1


unsigned int buf[ 1


int main( int argc , char* argv[ ] )


{


FILE *f ;


int i , j , k ;

if( ( f = fopen( "test.txt" , "r" ) ) == NULL )


{


printf( "Can"t Open The File" ) ;


return 0 ;


}


i=fread(pool,1,1


fread(buf,1,1,f); //B


i = 0 ;


while( !feof( f ) )


{

fscanf( f , "%c" , &pool[ i++ ] ) ;


}


fclose( f ) ; // C


return 0 ;


} */


/*


A 此時要注意的是,由於打開方式為"r"而不是"rb",則返回的值i不為讀入數據的真實長度.


B 此代碼本意為讀入一個位元組,存入buf[0]中,但是,由於buf為整型緩衝區,而實際上,fread會讀入四個字元來補滿buf[0],由此產生兩個問題:1,讀入數據不準確;2,由於文件指針移動了四而不是一,則下一個數據實際讀入的是文件的第五個位元組.


想要一起學習C 的可以加裙二四八八九四四三零,有很多大神一起學習交流,有資源,然後可以訂閱一下


C 此時要注意的是,最後i的值會比實際讀入數據多一個,正確的是,在最後補一條指令:i--;


*/


/*


// ================== 邊界 ==================


int main( int argc , char* argv[ ] )


{


char m_ca ;


unsigned char m_ucb ;


unsigned int i , j ;


char m_cBuf[ 257 ] ;


for( m_ca = 0 ; m_ca


{


m_cBuf[ m_ca ] = m_ca ; // A


}


for( m_ucb = 0 ; m_ucb


{


m_cBuf[ m_ucb ] = m_ucb ; // B


}


i = 0 ;


i-- ;


for( j = 0 ; j


{


}


}*/


/*


A 有符號的字元型值的範圍是 -127-128 ,這段代碼會讓你很爽的把內存改的亂七八糟,還是個死循環。。。


B 數組初始化只有一種結果:死循環 無符號字元型的表達範圍為 0- 255,永遠不可能達到 256


C 上述循環會運行2的32次方減一次 !!!


printf( "
%u
" , i ) ;


*/


/*


// ================== 編譯順序 ==================


int main( int argc , char* argv[ ] )


{


int i , j ;


i = 1 ;


j = 2 ;


printf( "
i = 1 , j = 2 , i += ( 4 + j ) = %d , i += 4 + j = %d
" , (i+=(4+j)) , (i+=4+j) ) ;


return 0 ;


}*/


/*


本例測試 += 操作時,右面的括弧有沒有用


(實際上,+=的右邊只算一個操作數,也就是右邊表達式的值。兩個+=的計算內容是一樣的,都是 i += ( 4 + j ) )


由於本條語句的編譯順序為從右向左,結果為:


Debug :


i = 1 , j = 2 , i += ( 4 + j ) = 13 , i += 4 + j = 7


Release :


i = 1 , j = 2 , i += ( 4 + j ) = 13 , i += 4 + j = 13


都不是原代碼的預期結果!!!!


看來採用這種高手編程技術可能會產生演算法的二義性.


編寫代碼的基本要求是安全可靠,既然可能產生問題,我的建議是 : 不採用這種技術


*/


/*


// ================== 計算精度 ==================


int main( int argc , char* argv[ ] )


{


// float(浮點型)的精度非常低,以下程序的最後結果,一般不會是 1


float m_fa , m_fb ;


m_fa = 1 / 12 ;


m_fb = m_fa * 12 ;


printf( "

Test Float : %12.10f
" , m_fb);


// 此時將數據類型改為double(雙精度),會有比較滿意的結果


double m_dfa , m_dfb ;


m_dfa = 1 / MAX_DOUBLE_NUMBER ;


m_dfb = m_dfa * MAX_DOUBLE_NUMBER ;


printf( "

Test Double : %12.10f
" , m_dfb);


// 結果依然是1.


// 要注意的是,在本例中,double能做的除法長度為10的20次方冪.再長就要採用大數演算法了。


return 0 ;


}


*/


/*


// ================== 邊界對齊 ==================


int main( int argc , char* argv[ ] )


{


//#pragma pack ( 1 )


struct Type_A


{


int a ;


char b ;


short c ;


} m_stTesta ;


struct Type_B


{


char b ;


int a ;


short c ;


} m_stTestb ;


//#pragma pack ( )


printf("
Struct A : %d Struct B : %d
" , sizeof( m_stTesta ) , sizeof( m_stTestb ) ) ;


return 0 ;


}


*/


/* 依照正常的方式來計算,兩個結構體的長度都應該是7,但實際結果是 8 和12


產生這個問題的原因就是編譯器的邊界對齊問題。


編譯器為了提高代碼效率,或者保證代碼正確運行,會對數據的起點進行相應的處理


例如:


有些CPU的數據起點必須為偶數,若為奇數則出錯;


有些CPU只能從偶數起點讀數據,若一個整型起點為偶數,則可一次讀入,若起點為奇數,則要兩次才能讀入


一般情況下,數據起點為2的n次冪,表現即為地址碼的某幾位低地址為0


VC編譯器在默認設定下,邊界對齊採用8位元組


但是,這只是對於大於八位元組的長度類型而言,採用八位元組邊界


在數據類型低於8位元組時,編譯器會採用最小符合條件的邊界來設定數據起點


這也就是在上述情況下 struct Type_A 的長度為 8 ,struct Type_B的長度為12


如果想讓這兩個結構體只有實際定義長度,我們必須通知編譯器,改變邊界對齊方式


方法一:


預編譯命令 : #pragma pack( [ n ] ) 與 #pragma pack( )


#pragma pack( [ n ] ) 通知編譯系統,以下代碼採用 n位元組長的邊界 ,n = 1 , 2 , 4 , 8 , 16


#pragma pack( ) 通知編譯系統,結束上面的邊界對齊方式,以下採用默認方式


方法二:


VC IDE 中設定編譯命令:


[Project]|[Settings],[c/c++]選項卡[Category]的[Code Generation]選項


[Struct Member Alignment]中修改,默認是8位元組。


我個人不推薦使用IDE的修改,IDE的修改,意味著全部編譯代碼均採用這種新的邊界對齊方式,會對某些代碼產生影響


(預編譯命令#pragma 的內容比較多,可以參考MSDN中#pragma的詳細說明,eg: #pragma comment( lib , "ws2_32.lib" ) )


*/


/*


// ================== 指針與逗號語句 ==================


#define HOST_c2l( c , l ) ( l = ( ( ( unsigned long ) ( *( ( c )++ ) ) )


l |= ( ( ( unsigned long ) ( *( ( c )++ ) ) )


l |= ( ( ( unsigned long ) ( *( ( c )++ ) ) )


l |= ( ( ( unsigned long ) ( *( ( c )++ ) ) ) ) ,


l )


int main( int argc , char* argv[ ] )


{


unsigned char m_caData[ 256 ] ;


unsigned char *m_cpPoint ;


unsigned int *m_ipPoint ;


int i , l ;


m_cpPoint = m_caData ;


m_ipPoint = ( unsigned int * ) m_caData ;


printf( "
SIZEOF_POINT " ) ;


printf( "
CHAR_SIZEOF : %08x - INT_SIZEOF : %08x " , sizeof( m_cpPoint ) , sizeof( m_ipPoint ) ) ;


for( i = 0 ; i


{


m_caData[ i ] = ( i + 1 ) % 0xff ;


}


printf( "

POINT START " ) ;


printf( "
CHAR %p : %08x - %08x " , m_cpPoint , m_cpPoint , *m_cpPoint ) ;


printf( "
INT %p : %08x - %08x " , m_ipPoint , m_ipPoint , *m_ipPoint ) ;


printf( "

POINT + 4 " );


m_cpPoint += 4 ;


m_ipPoint += 4 ;


printf( "
CHAR %p : %08x - %08x %08x ", m_cpPoint , m_cpPoint , *m_cpPoint , *m_cpPoint + 6 ) ;


printf( "
INT %p : %08x - %08x %08x ", m_ipPoint , m_ipPoint , *m_ipPoint , *m_ipPoint + 6 ) ;


printf( "

, COMMAND AND CHAR_POINT MOVEMENT : " ) ;


i = HOST_c2l( m_cpPoint , l ) ;


printf( "
CHAR %p : %08x " , m_cpPoint , *m_cpPoint ) ;


printf( "

I : %08x L: %08x

" , i , l ) ;


return 0 ;


}*/


/*


1. printf( "%p" , XXXX ) 輸出為XXXX的地址


2. 指針本身只是一個地址入口(四位元組) , 任意指針 sizeof( p ) 只有一個結果 : 4 .


3. *p 為指針內容,p 為指針地址


4. 整型指針指向字元型緩衝區時,採用intel數據排列順序,以四位元組為單位進行反序


5. ( p + 1 ) 表示根據指針定義的單元長度加1,若定義為字元指針,則只加一位元組,若為整型,則加四位元組


6. 逗號語句的計算順序為自左向右,逗號語句的值為逗號語句的最後一個分量的值.


7. 指針C在每個逗號後就指向下一個字元,運算後,C的指針值變為 C + 4 .


8. l的值每個都在變化,最後的l,即四個字元的並,做為這個表達式的值,可以直接做為賦值使用.


*/


/*


// ================== 指針應用 ==================


#include "malloc.h"


#pragma pack ( 1 )


typedef struct MY_IP_HEAD { unsigned char Ver_Len ;


unsigned int Source_IP ;


unsigned int Dest_IP ; } *IPHEAD , TEST_LEN;


#pragma pack ( )


int main( int argc , char* argv[ ] )


{


char *Buf ;


unsigned char *Point ;


TEST_LEN test ;


IPHEAD ip_point ;


int i , j ;


Buf = ( char * )malloc( 1


for( i = 0 ; i


{


Buf[ i ] = i + 1 ;


}


Point = (unsigned char * ) Buf ;


for( i = 0 ; i


{


ip_point = ( IPHEAD ) Point ;


printf( "
STEP : %2d" , i ) ;


printf( "
Buf : " ) ;


for( j = 0 ; j


{


printf( "%02x " , Point[ j ] ) ;


}


printf( "
IP : " ) ;


printf( "VER : %02x S : %08x D : %08x " ,


ip_point->Ver_Len , ip_point->Source_IP , ip_point->Dest_IP ) ;


Point += 60 ;


}


free( Buf ) ;


Buf = NULL ;


return 0 ;


}*/


/*


指針是地址,指針也只是地址,這點一定要牢記


在這裡,我們採用一個簡單的例子,一個無符號的字元串指針,一個IP包的結構體指針


第一個指針賦值之後,會強制將有符號字元變為無符號字元,沒有任何額外的開銷(告別&0xff了)


第二個指針賦值之後,當我們引用指針時,會自動將字元數據變成整型了( 告別了(l=(a


美中不足的是,又是intel數據排列方式的問題,四個位元組做了一個反序


這裡要注意的是,如果不採用預編譯命令對結構體長度進行處理的話,結果不會令人滿意


與此類似的就是,結構體的位段,採用的是從右向左的編排順序


*/


/*


// ================== 死循環 ==================


//#include "windows.h"


int main( int argc , char* argv[ ] )


{


while(1)


{


// ::Sleep(1); //停頓1/1000秒


}


return 0 ;


}


*/


/*


很多時候,我們工作中會用到死循環


在這種情況下,CPU的佔用率會非常高,表現就是明顯感覺機器運行很慢


雙核情況下,佔有率一般都超過50%,估計在單核情況下,就是100%(沒單核CPU測試)


解決方案:


添加頭文件包含: #include "windows.h"


在循環體內加入下列代碼: ::Sleep(1); //停頓1/1000秒


這種處理之後,一般雙核的CPU,資源佔用率不會超過15%


*/


/*


// ================== 文件系統 ==================


#define FILE_NUMEBER ( 2000 )


int main( int argc , char* argv[ ] )


{


FILE *f ;


char name[ 256 ] ;


int i ;


for( i = 0 ; i


{


sprintf( name , "%04d.txt" , i ) ;


if( ( f = fopen( name , "w" ) ) == NULL )


{


printf("
Can"t Creat File %s " , name ) ;


return 0 ;


}


fprintf( f, " %04d" , i ) ;


fclose( f ) ;


}


return 1 ;


}


*/


/*


在win系統中,我們進入文件夾後,win文件系統會對這個文件夾下的文件進行一次遍歷以構造一個數據表


顯然,文件數目越多,時間越長(要不停地開內存來放數據,重構數據表)


運行上面的代碼後,打開那個文件夾,你會發現,系統很慢,如果不慢,FILE_NUMEBER 後面的數字改成20000 想要一起學習C 的可以加裙二四八八九四四三零,有很多大神一起學習交流,有資源,然後可以訂閱一下


一般建議一個文件夾下面最多放1000個文件


我最近碰到一兄弟,一文件夾下面放2W個文件!!


機器的情況是:系統不穩定,老死機(不死才怪,一開這個文件夾,win不崩潰都算是奇蹟了)


*/


/*


// ================== 改變演算法流程 ==================


unsigned int Test( unsigned int uCur )


{


return ( ( uCur


}


int main( int argc , char* argv[ ] )


{


Test( 3 ) ;


return 0 ;


}


*/


/*


你能馬上告訴我,Test( 3 ) 的返回值是幾嗎? 我是做不到的


對這個演算法的第一種改進,就是將這個表達式分解成正規的if else 模型


但是,如果只是想到改進,那你就大錯特錯了,其實有更好的辦法來實現這個問題


// 分支法


unsigned int Test( unsigned int uCur )


{


ASSERT( uCur >= 0 && uCur


if( uCur == 1 )


{


return 0 ;


}


if( uCur == 4 )


{


return 2 ;


}


return ( uCur + 1 ) ;


}


// 列表法


unsigned int Test( unsigned int uCur )


{


static const unsigned int uReturn[ ] = { 1, 0 , 3 , 4 , 2 } ;


ASSERT( uCur >= 0 && uCur


return ( uReturn[ uCur ] ) ;


}


*/


// ================== 改變演算法模型 ==================


/*


某程序員為一個ftp伺服器寫一段代碼,不允許用戶上傳可執行代碼


一般可執行代碼的擴展名為: bat,com,exe,於是,生成下面的匹配表


char Refuse_File[ 3 ][ ] = { "bat" , "com" , "exe" } ;


但是,過了幾天,他發現,其實MS_WORD家族的文件類型也是可以執行的,於是,在上面的列表中,添加如下:


char Refuse_File[ 5 ][ ] = { "bat" , "com" , "exe" ,"doc","ppt" } ;


再過了幾天,他又發現,網頁文件也是可執行的,於是,繼續添加列表


char Refuse_File[ 8 ][ ] = { "bat" , "com" , "exe" ,"doc","ppt","htm","html","asp" ,"php" } ;


又過了幾天,發現其實資料庫文件,也有機會執行,繼續這個動作....


到此為止了,我們可以肯定的說,這個列表總會在不停地增漲,無論是從代碼實現的安全功能還是執行效率來說,


這個模型都不理想.


現在,讓我們回到起點,這段代碼到底要做什麼?


不允許用戶上傳可執行代碼


解決這個問題有幾種方法?


1,不允許用戶上傳可執行代碼


2,允許上傳不可執行代碼!!!!


如果我們採用第二套方案,將否定策略改成肯定策略,這個問題就很輕鬆了


想要一起學習C 的可以加裙二四八八九四四三零,有很多大神一起學習交流,有資源,然後可以訂閱一下


顯然這個列表會很小,安全性和效率都得到了很好的解決


這個故事只是想告訴我們,一般情況下,任何問題都有二義性,不要只知其一不知其二


做不出好演算法,不是你不努力,而是你考慮不全面


這段時間工作太忙,都不知道哪兒來這麼多事....


把我前段時間整理出來的問題貼一合集,這是我這十年左右時間碰到的代碼設計問題,都是些小問題,但是,越是小問題,越是不好解決,希望對大家有所幫助.


有句話說的好,你有一個思想,我有一個思想,大家交流一下,就是兩個思想,共同進步吧.


// test.cpp : Defines the entry point for the console application.


//


#include "stdafx.h"


// 編寫代碼的幾類問題


// 1 fscanf


// 2 文件操作


// 3 變數邊界


// 4 編譯順序


// 5 計算精度


// 6 邊界對齊


// 7 指針與逗號語句


// 8 指針應用


// 9 死循環


// 10 文件系統


// 11 改變演算法流程


// 12 改變演算法模型


/*


// ================== fscanf() ==================


// test.txt : 1 2 3 4 5 6 7 8 9 0 1 2


int main( int argc , char* argv[ ] )


{


FILE *f ;


char buf[ 11] ;


int i ;


if( ( f = fopen( "test.txt" , "r" ) ) == NULL )


{


printf( "Can"t Open The File" ) ;


return 0 ;


}


for( i = 0 ; i


{


//fscanf( f , "%x" , &buf[ i ] ) ; // A


fscanf( f , "%x" , &buf[ 9-i ] ) ; // B


}


fclose( f ) ;


printf( "
End : " ) ;


for( i = 0 ; i


{


printf( "%02x " , buf[ i ] ) ;


}


printf( "
" ) ;


return 0;


}*/


/*


這段代碼完成的工作就是將文件中的十個數字,從9-0反序放到數組buf中,但是,在實際執行過程中,有下面兩個問題


1. 會產生溢出錯誤....,A,B均有


2. 在B方式下,輸出結果全0


這個問題實在是有點讓人莫名其妙的


給大家一個分析這個問題的辦法,在//B方案下面添加如下代碼:


printf( "
NO.%d : " , i ) ;


for( int j = 0 ; j


{


printf( "%02x " , buf[ j ] ) ;


}


分析:


1. fcanf("%x")做為一個(四位元組)整型X讀入,然後強制&0xff( char),然後,按照intel數據順序,低位在前,高位在後,寫四個位元組,在A,B方式下,問題1均是由於對buf[9]的賦值產生的邊界溢出造成的,buf的緩衝區長度最少應為13.......OMG


2 .在B方式下,由於一次對四個位元組賦值,從數組尾向前的運動方式,使的數組從後向前逐個賦0!!


1 int buf[10 ];


2 char a;


fscanf(f,"%x",&a);


buf[9-i]=a&0xff;


寫這個例子只是想告訴大家,其實很多時候,代碼本身是沒錯的,錯在系統,大家要學代碼設計,一定要記住,任何代碼都是在一定的環境下實現的,要想寫好代碼,一定要對代碼的應用環境有充分的認識。


想要一起學習C 的可以加裙二四八八九四四三零,有很多大神一起學習交流,有資源,然後可以訂閱一下


*/


/*


// ================== 文件操作 ==================


unsigned char pool[ 1


unsigned int buf[ 1


int main( int argc , char* argv[ ] )


{


FILE *f ;


int i , j , k ;


if( ( f = fopen( "test.txt" , "r" ) ) == NULL )


{


printf( "Can"t Open The File" ) ;


return 0 ;


}


i=fread(pool,1,1


fread(buf,1,1,f); //B


i = 0 ;


while( !feof( f ) )


{


fscanf( f , "%c" , &pool[ i++ ] ) ;


}


fclose( f ) ; // C


return 0 ;


} */


/*


A 此時要注意的是,由於打開方式為"r"而不是"rb",則返回的值i不為讀入數據的真實長度.


B 此代碼本意為讀入一個位元組,存入buf[0]中,但是,由於buf為整型緩衝區,而實際上,fread會讀入四個字元來補滿buf[0],由此產生兩個問題:1,讀入數據不準確;2,由於文件指針移動了四而不是一,則下一個數據實際讀入的是文件的第五個位元組.


C 此時要注意的是,最後i的值會比實際讀入數據多一個,正確的是,在最後補一條指令:i--;


*/


/*


// ================== 邊界 ==================


int main( int argc , char* argv[ ] )


{


char m_ca ;


unsigned char m_ucb ;


unsigned int i , j ;


char m_cBuf[ 257 ] ;


for( m_ca = 0 ; m_ca


{


m_cBuf[ m_ca ] = m_ca ; // A


}


for( m_ucb = 0 ; m_ucb


{


m_cBuf[ m_ucb ] = m_ucb ; // B


}


i = 0 ;


i-- ;


for( j = 0 ; j


{


}


}*/


/*


A 有符號的字元型值的範圍是 -127-128 ,這段代碼會讓你很爽的把內存改的亂七八糟,還是個死循環。。。


B 數組初始化只有一種結果:死循環 無符號字元型的表達範圍為 0- 255,永遠不可能達到 256


C 上述循環會運行2的32次方減一次 !!!


printf( "
%u
" , i ) ;


*/


/*


// ================== 編譯順序 ==================


int main( int argc , char* argv[ ] )


{


int i , j ;


i = 1 ;


j = 2 ;


printf( "
i = 1 , j = 2 , i += ( 4 + j ) = %d , i += 4 + j = %d
" , (i+=(4+j)) , (i+=4+j) ) ;


return 0 ;


}*/


/*


本例測試 += 操作時,右面的括弧有沒有用


(實際上,+=的右邊只算一個操作數,也就是右邊表達式的值。兩個+=的計算內容是一樣的,都是 i += ( 4 + j ) )


由於本條語句的編譯順序為從右向左,結果為:


Debug :


i = 1 , j = 2 , i += ( 4 + j ) = 13 , i += 4 + j = 7


Release :


i = 1 , j = 2 , i += ( 4 + j ) = 13 , i += 4 + j = 13


都不是原代碼的預期結果!!!!


看來採用這種高手編程技術可能會產生演算法的二義性.


編寫代碼的基本要求是安全可靠,既然可能產生問題,我的建議是 : 不採用這種技術


*/


/*


// ================== 計算精度 ==================


int main( int argc , char* argv[ ] )


{


// float(浮點型)的精度非常低,以下程序的最後結果,一般不會是 1


float m_fa , m_fb ;


m_fa = 1 / 12 ;


m_fb = m_fa * 12 ;


printf( "

Test Float : %12.10f
" , m_fb);


// 此時將數據類型改為double(雙精度),會有比較滿意的結果


double m_dfa , m_dfb ;


m_dfa = 1 / MAX_DOUBLE_NUMBER ;


m_dfb = m_dfa * MAX_DOUBLE_NUMBER ;


printf( "

Test Double : %12.10f
" , m_dfb);


// 結果依然是1.


// 要注意的是,在本例中,double能做的除法長度為10的20次方冪.再長就要採用大數演算法了。


return 0 ;


}


*/


/*



C語言——老江湖不容忽視的新問題你有遇到嗎?



想要一起學習C 的可以加裙二四八八九四四三零,有很多大神一起學習交流,有資源,然後可以訂閱一下

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 C加加 的精彩文章:

C語言程序員與程序員老婆的故事
c語言編程之C語言學習技巧
C語言編程過程中的一些建議
想要學習C語言C加加?C語言C加加入門書籍推薦
《C語言陪我們快半個世紀,有人說它老了,你認為呢》

TAG:C加加 |

您可能感興趣

產後抑鬱?這是不容忽視的問題
大姨媽不準時?這幾個問題不能忽視!
頭髮泄露你的健康問題?為什麼不早點讓我看到?
花卉換盆最容易忽略的問題,你也還不知道?
瑜伽沒有問題,你才有問題
翡翠開光的講究真不少,看看你都注意到這些問題了嗎
」我的青春戀愛物語果然有問題「這部動漫有人看懂了嗎?
看懂這些,認識篆字不是問題 ?
有問題就解決問題吧,搞不死你的只會讓你看起來更帥氣啊!
孕前最容易被雙方忽視的幾個問題,你知道嗎?
做功問題搞不懂?解題思路點開看!
某火影迷問的幾個問題,不知道有沒有大神能解答?
老子道德經勸言:做人不可死板,遇到問題要懂得這樣去看
杜哥講史:琦善,老江湖遇到了新問題
你挽回愛情中有這些常見問題嗎?
我說的話孩子怎麼就聽不進去呢?也許你說話的方式有問題!
養君子蘭最煩惱的4大問題,看看你有沒遇到?
初婚會遇到很多你想像不到的問題
當心,女人癢乳頭癢不是什麼好事,這類問題真的不容忽視!