我无法理解struct指针和XOR的这种行为
我第一次使用struct指针,我似乎无法弄清楚这里发生了什么.我的测试应用xor的基本属性,即x ^ y ^ y = x,但不是在C?
下面的代码在我的主程序中,并准确地恢复所有“测试”字母(我继续在屏幕上打印,但我省略了很多垃圾,以便将这个问题保持简短(呃)).结构“aes”指的是这个定义: typedef uint32_t word; struct aes { word iv[4]; word key[8]; word state[4]; word schedule[56]; }; 正如上下文所暗示的那样,封装项目是AES实现(我试图通过尝试新技术来加速我当前的实现). 在我的测试中,make_string和make_state可靠地工作,即使在有问题的函数中,但是为了参考: void make_string (word in[],char out[]) { for (int i = 0; i < 4; i++) { out[(i * 4) + 0] = (char) (in[i] >> 24); out[(i * 4) + 1] = (char) (in[i] >> 16); out[(i * 4) + 2] = (char) (in[i] >> 8); out[(i * 4) + 3] = (char) (in[i] ); } } void make_state(word out[],char in[]) { for (int i = 0; i < 4; i++) { out[i] = (word) (in[(i * 4) + 0] << 24) ^ (word) (in[(i * 4) + 1] << 16) ^ (word) (in[(i * 4) + 2] << 8) ^ (word) (in[(i * 4) + 3] ); } } 无论如何,这是工作的块.正是这个功能,我试图通过将其存放在一个函数中来模块化: char test[16] = { 'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p' }; aes cipher; struct aes * work; work = &cipher; make_state(work->state,test); work->state[0] ^= 0xbc6378cd; work->state[0] ^= 0xbc6378cd; make_string(work->state,test); 虽然这段代码有效,但通过将它传递给函数来做同样的事情却不会: void encipher_block (struct aes * work,char in[]) { make_state(work->state,in); work->state[0] ^= 0xff00cd00; make_string(work->state,in); } void decipher_block (struct aes * work,in); } 然而,通过在加密和解密中删除make_state和make_string调用,它按预期工作! make_state(work->state,test); encipher_block(&cipher,test); decipher_block(&cipher,test); make_string(work->state,test); 所以要澄清一下,我没有问题!我只是想了解这种行为. 解决方法
将char更改为unsigned char. char可能已签名,可能在您的系统上,这会在转换为其他整数类型和转换时导致问题.
在make_string中的表达式(char)(在[i]>>> 24中),无符号的32位整数被转换为带符号的8位整数(在C实现中).此表达式可以将值转换为char中不可表示的char,特别是128到255之间的值.根据C 2011 6.3.1.3 3,结果是实现定义的或引发实现定义的信号. 在make_state中的表达式(word)(在[(i * 4)3]中),[…]中的char是一个带符号的8位整数(在C实现中).根据C 2011 6.3.1.1中定义的常规整数提升,将此char转换为int 2.如果char为负数,则生成的int为负数.然后,当它被转换为无符号的字时,效果是符号位以高24位复制.例如,如果char的值为-166(0x90),则结果为0xffffff90,但您需要0x00000090. 在此代码中将char更改为unsigned char. 另外,在make_state中,在[(i * 4)0]中应该在左移之前转换为单词.这是因为它将作为unsigned char启动,在转换之前将其提升为int.如果它具有高位设置的某个值,例如0x80,则将其向左移位24位会产生一个无法用int表示的值,例如0x80000000.根据C 2011 6.5.7 4,行为未定义. 这在大多数C实现中不会成为问题;二进制补码通常用于有符号整数,结果将根据需要进行换行.另外,我希望这是编译器开发人员设计的模型情况,因为它是一种非常常见的代码结构.但是,为了提高可移植性,逐字转换将避免溢出的可能性. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |