相關的,但是從有些不同,Do any compilers transfer effective type through memcpy/memmove類型無關的memcpy在C99
在C89,memcpy
和memmove
需要表現得好像源和目標正在使用的字符類型訪問,複製的所有位源到目的地而不考慮被複制的數據的類型。
C99更改了語義,因此如果將具有有效類型的對象複製到沒有聲明類型的存儲器(通常是從malloc或其他此類函數接收到的存儲器),它將在目標存儲器中創建一個只能訪問的對象使用源類型。
例如,以下代碼將在C89上具有完全定義的行爲 「unsigned int」和「unsigned long」具有相同的32位表示但在C99下具有未定義行爲的所有平臺。
#include <stdio.h>
#include <string.h>
void increment_32_bit_uint(void *p)
{
uint32_t temp;
memcpy(&temp, p, sizeof temp);
temp++;
memcpy(p, &temp, sizeof temp);
}
int main(void)
{
unsigned *ip = malloc(sizeof (unsigned));
unsigned long *lp = malloc(sizeof (unsigned long));
*ip = 3; *lp = 6;
increment_32_bit_uint(ip);
increment_32_bit_uint(lp);
printf("%u %lu", *ip, *lp);
return 0;
}
根據C99的規則,通過分配存儲到「increment_32_bit_uint」功能將使其設置有效的類型來uint32_t的,不能是同一類型的兩個「簽名」和「無符號長」,即使所有三個類型具有相同的表示形式。因此,即使該類型具有相同的表示形式,編譯器也可以使用它讀取該存儲的代碼來執行任何類似於uint32_t的類型的代碼。
在C99或C11中,是否有任何方式執行副本,使得編譯器能夠生成高效的代碼,但會強制編譯器將目標視爲包含一個沒有有效的類型[因此可以使用任何類型訪問]?
海合會包括''和'' –
xvan
@xvan後編譯使用沒有警告'-std = c99'或'-std = c11'您的例子:一個特定的編譯器(或者甚至每一個編譯器目前存在)恰巧做了一些事情並不意味着標準強制要求繼續這樣做。有幾種情況幾乎每個編譯器都存在數十年沒有標準要求它們這樣做的相同行爲,直到一些編譯器作者認爲他們不再需要支持這些情況,所以代碼在當今所有編譯器並不意味着它不會調用UB。 – supercat
@xvan:Per N1570:「如果使用memcpy或memmove將值複製到沒有聲明類型的對象中,或者將其複製爲字符類型的數組,則該訪問和後續訪問的修改對象的有效類型不修改該值的值是從中複製該值的對象的有效類型,如果它有一個。「我沒有看到說有效類型不會被設置爲「uint32_t」,也沒有任何其他類型的讀取不會調用未定義行爲。 – supercat