看板 C_and_CPP 關於我們 聯絡資訊
※ 引述《OoShiunoO (機機勳)》之銘言: : 接著上篇,我其實還有一個問題..... : 上一篇我用的函式叫做nextbits() : 假如我現在有一段code如下 : do{ : ........... : }while(nextbits(fp)==sequence_header_code) : 我把fp這個指向檔案的指標傳給nextbits這個函式,希望他傳回一個東西能夠跟 : sequence_header_code來做比較,我應該怎麼改寫上一篇的函式呢...? : unsigned char sequence_header_code[4]={0x00,0x00,0x01,0xb3}; : void nextbits(FILE *f){ : unsigned char sum[4]; : fread( sum, sizeof(sum), 1, f ); : if( !memcmp( sum,sequence_header_code,sizeof(sum) ) ){ printf("match");} : } : 就是說我希望不要在這個函式裡面做比較,這個函式只要能把讀到的值存到某 : 個array裡面,再傳出來就好了,比較的動作,就拿到外面來做。 : 不知道把sum傳出來要怎麼寫呢...? 以下條列內容請參考 ISO C n1256 [6.2.5/27] A pointer to void shall have the same representation and alignment requirements as a pointer to a character type. Similarly, pointers to qualified or unqualified versions of compatible types shall have the same representation and alignment requirements. All pointers to structure types shall have the same representation and alignment requirements as each other. All pointers to union types shall have the same representation and alignment requirements as each other. Pointers to other types need not have the same representation or alignment requirements. 上面點出了使用 reinterpret_cast 的危險性, 除非你知道具體實作是如何, 否 則無法保證指標互轉不會出問題. - 再者就是內建整數型態並無保證假如其佔有記憶體 N bytes, 其最大無號數極限 確實是 2^N - 1, 意味著實作品可以在中間加上paddings, 所以就算指標可以安 全互轉(通常是可以的), 以下程式碼也不一定正確(假設 sizeof(int) == 4): unsigned char a[] = { '\x12', '\x34', '\x56', '\x78' }; assert( 0x78563412 == *(int*)a || 0x12345678 == *(int*)a ); 比起對 string literal 做 dereference 還安全(還需要注意隱含的cv-qualifier). - endian 當然還是小問題, 剩下能安全使用的整數型態大概剩 <stdint.h>裡所定 義的了: [7.18.1.1/1] The typedef name intN_t designates a signed integer type with width N, no padding bits, and a two's complement representation. Thus, int8_t denotes a signed integer type with a width of exactly 8 bits. [7.18.2.1/1] — minimum values of exact-width signed integer types INTN_MIN exactly -(2^(N-1)) — maximum values of exact-width signed integer types INTN_MAX exactly 2^(N-1) - 1 — maximum values of exact-width unsigned integer types UINTN_MAX exactly 2^N - 1 - 為了避免掉這些奇怪問題, 我會乖乖使用 memcmp 來實作: uint8_t* nextbits( uint8_t *sum, FILE *f ) { fread( sum, sizeof(uint8_t), 4, f ); return sum; } int main() { // definitions... do { // something here }while( !memcmp( nextbits(sum, fp), sequence_header_code, 4 ) ); } - 「常見」means nothing. 寫下一段程式碼需要了解的除其運行結果, 其隱藏對 系統的假設、前/後置條件、語意也很重要, 這是心法跟招式的差別, 就連加一 個小小的 const, 整個程式碼就是不一樣. -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.121.197.115
firejox:其實只要事先處理也可以不用memcmp... 06/12 20:45
若知道memory layout, 當然也可以不用 memcmp, 但這僅僅只是功 能上相同而已, 不妨將其實作出來, 然後過一兩個月再回來維護你 「過早最佳化」的成品. 執行速度雖然很誘人, 但這並不是一份程式的全部. 寫系統程式和 應用程式考慮的面向不同, 不是別人怎麼用你就該怎麼用這樣.
cole945:"比起對 string literal...還安全" 的安全點在哪 @@? 06/12 21:11
可參考 n1256 [6.4.5/6] It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined. 實作品可以決定string literal所代表的陣列是否唯讀, 或者共用 同一塊記憶體, 假如是此種組合: modifiable + distinct char *a = "\xb4", *b = "\xb4"; *a = 'a'; assert( *b == '\xb4' ); 便會產生非預期的結果.
firejox:首先 我不是原來的發問者 要我維護那半成品有點牽強 06/12 21:49
firejox:而我們也只知道一部份而已 06/12 21:49
我不是說這份, 而是使用同樣手法的其他程式.
firejox:再說過了一兩個月之後 06/12 21:52
firejox:我也不知道要怎麼再維護 "過早最佳化的成品" 06/12 21:53
firejox:對於我而言 指標互轉的問題,只要不要跑掉就可以確保了 06/12 21:58
這是會不會 slice掉的問題...
cole945:最初的case並沒有要修改seq呀 @@ 06/12 22:16
對於那些未在 ponter to string literal 加上 const修飾字的程 式片段, 若不小心改到, 整合時也會影響這邊的. 倒是不懂為啥多 數 code都不會加就是了 @"@
firejox:只要確保指向空間是否在可視範圍內即可呀 06/12 22:29
firejox:說真的 memcpy等也只不過是切成最小單位去做罷了 06/12 22:30
所以其他問題還是要交給使用者傷腦筋呀~ 最懶人的方法就是全都 用array of chars來做 ※ 編輯: loveme00835 來自: 140.121.197.115 (06/12 22:35)
cole945:嗯對呀@.@/ 我覺得重點變成應該是要const char*呀 囧 06/12 22:35
cole945:const char*是compiling time就能emit error的.. 06/12 22:35
cole945:不過這樣寫的code不多..|| 06/12 22:36
cole945:@fj, 其實unalign的問題在非x86蠻容易炸掉的.. 06/12 22:39
cole945:而且這是runtime才會遇到的..所以不建議從char*去取值@@ 06/12 22:39
angleevil:雖然算結案了,不過string literal型態還是用const char* 06/13 21:10