
#include <stdio.h> #include <stdlib.h> #include <string.h> /* unsigned long to string */ cha * ultostr(unsigned long value, char * ptr, int base); int main(void) { char var[] = "0A84010000000301"; unsigned long value = strtoul(var, NULL, 16); printf("value is %lu\n\n", value); char * str; ultostr(value, str, 16); printf("Received '%s'\n\n", str); return 0; } /* unsigned long to string */ char* ultostr(unsigned long value, char* ptr, int base) { unsigned long t = 0, res = 0; unsigned long tmp = value; int count = 0; if (NULL == ptr) { return NULL; } if (tmp == 0) { count++; } while (tmp > 0) { tmp = tmp / base; count++; } ptr += count; *ptr = '\0'; do { res = value - base * (t = value / base); if (res < 10) { *--ptr = '0' + res; } else if ((res >= 10) && (res < 16)) { *--ptr = 'A' - 10 + res; } } while ((value = t) != 0); return(ptr); } VS2019 提示使用了未初始化的局部变量 str,但是 gcc 编译就没出问题,gcc 是 8.3.0
这是为啥?
把指针变量 str 稍微修改了一下,现在 VS2019 编译不会出错了,但是 Windows 平台和 Linux 平台的结果为什么会不一样
结果
# Linux下 value is 757731736816714497 Received 'A84010000000301' # Windows下 value is 4294967295 Received 'FFFFFFFF' 源码
#include <stdio.h> #include <stdlib.h> #include <string.h> /* unsigned long to string */ char * ultostr(unsigned long value, char * ptr, int base); int main(void) { char var[] = "0A84010000000301"; unsigned long value = strtoul(var, NULL, 16); printf("value is %lu\n\n", value); int size = sizeof(var); char * str = malloc(size + 1); ultostr(value, str, 16); printf("Received '%s'\n\n",str); return 0; } /* unsigned long to string */ char* ultostr(unsigned long value, char* ptr, int base) { unsigned long t = 0, res = 0; unsigned long tmp = value; int count = 0; if (NULL == ptr) { return NULL; } if (tmp == 0) { count++; } while (tmp > 0) { tmp = tmp / base; count++; } ptr += count; *ptr = '\0'; do { res = value - base * (t = value / base); if (res < 10) { *--ptr = '0' + res; } else if ((res >= 10) && (res < 16)) { *--ptr = 'A' - 10 + res; } } while ((value = t) != 0); return(ptr); } 经 @ysc3839 指点,使用 unsigned long long 数据类型就可以使 Windows上与Linux上结果一致了。
感谢各位的帮助!
更正后
#include <stdio.h> #include <stdlib.h> #include <string.h> /* unsigned long long to string */ char * ultostr(unsigned long long value, char * ptr, int base); int main(void) { char var[] = "0A84010000000301"; unsigned long long value = strtoull(var, NULL, 16); printf("value is %llu\n", value); int size = sizeof(var); char * str = malloc(size); ultostr(value, str, 16); printf("Received '%s'\n",str); free(str); return 0; } /* unsigned long long to string */ char* ultostr(unsigned long long value, char * ptr, int base) { unsigned long long t = 0, res = 0; unsigned long long tmp = value; int count = 0; if (NULL == ptr) { return NULL; } if (tmp == 0) { count++; } while (tmp > 0) { tmp = tmp / base; count++; } ptr += count; *ptr = '\0'; do { res = value - base * (t = value / base); if (res < 10) { *--ptr = '0' + res; } else if ((res >= 10) && (res < 16)) { *--ptr = 'A' - 10 + res; } } while ((value = t) != 0); return(ptr); } 1 codehz 2021-03-04 10:06:06 +08:00 via Android 好家伙,你这 str 准备存哪里,编译不炸运行时炸的节奏(没炸也是运气好) |
2 commoccoom OP @codehz 但是为啥 gcc 没报错 |
3 venicejack 2021-03-04 10:09:03 +08:00 gcc 肯定是报 warning 了,编译成功不代表运行不 core |
4 rocksolid 2021-03-04 10:11:03 +08:00 侧面印证了 Visual Studio 果然是宇宙第一 IDE |
5 aloxaf 2021-03-04 10:11:26 +08:00 因为你没加 `-Wall -Wextra -Werror`,加了 gcc 就也会拒绝编译了( |
6 ReVanTis 2021-03-04 10:17:39 +08:00 关掉 sdl 检查或者去掉编译器的 /sdl 选项,msvc 也可以编译过 |
7 ReVanTis 2021-03-04 10:19:03 +08:00 @ReVanTis https://stackoverflow.com/questions/18559425/how-to-ignore-uninitialized-variable-error-in-msvc 用这个宏应该也可以 #pragma warning (disable: 4703) 在某些特殊场景下,不排除需要这么做的可能性 |
8 IDAEngine 2021-03-04 10:24:25 +08:00 还是 VS 专业些 |
9 commoccoom OP https://gist.githubusercontent.com/yloveyy/77bf89ff4b249e67185d99de81d3a1d7/raw/c923dba61b4962c66a3ee5faf60bfeefbd632a28 修改了一下,加了 int size = sizeof(var); char * str = malloc(size + 1); 但是 Windows 平台和 Linux 平台运行的结果不一样,Linux 运行符合预期,但是 Windows 结果 value is 4294967295 Received 'FFFFFFFF' 为啥。。。。 |
10 pisc 2021-03-04 10:30:44 +08:00 via Android 楼上都答不到点上来啊 @commoccoom 因为这个程序本来就是合法的,没有错,但这么用很危险,所以 vs 默认把这种“警告级别”升级为了“编译错误”,因为本身程序是合法的,所以 GCC 编译成功是没问题的,但一般会有警告信息,GCC 也可以配置成 |
11 xdeng 2021-03-04 10:31:38 +08:00 指针变量 除非你有十足的把握 否则应该给默认值 null |
12 aloxaf 2021-03-04 10:42:12 +08:00 @commoccoom 盲猜你 Windows 是 32 位的(或者默认编译 32 位程序 |
13 moonmagian 2021-03-04 10:47:19 +08:00 via iPhone 局部变量的初始值是和 os 相关的随机值,gcc 编译能跑只是因为随机的地址恰好可读可写而且不会覆盖其他内存里的东西。即使偶尔能跑,多跑几次或者换台机器跑就不一定了... |
14 aloxaf 2021-03-04 10:48:26 +08:00 |
15 newmlp 2021-03-04 10:58:07 +08:00 说明 gcc 就是辣鸡编译器 |
16 yuruizhe 2021-03-04 11:12:07 +08:00 @newmlp 好家伙,Apache 沉默 GUN 流泪 |
18 iyezi 2021-03-04 12:27:39 +08:00 @commoccoom #9 可能 sizeof 求出来的是一个指针的 size 吧。你想写的是不是 strlen ? |
19 littlewing 2021-03-04 12:38:54 +08:00 via iPhone 说明 linux 辣鸡,windows 天下第一 翻译一下就是 linus 辣鸡,印度啊三天下第一 |
20 littlewing 2021-03-04 12:41:02 +08:00 via iPhone @littlewing 对了,还得加上 GNU 辣鸡,所以 RMS 辣鸡 |
21 ysc3839 2021-03-04 12:41:28 +08:00 via Android 第一个问题是指针变量未初始化就使用。 第二个问题是 unsigned long 在不同平台上长度不一致,建议改成 strtoull 。 |
22 commoccoom OP @iyezi 这个对结果没有影响吧 |
23 CismonX 2021-03-04 12:45:04 +08:00 用 gcc/clang 编译的时候,加参数 -Wall -Wextra -Wpedantic 是基操,加上以后可以看到如下警告: warning: variable 'str' is uninitialized when used here [-Wuninitialized] |
24 felixcode 2021-03-04 13:01:06 +08:00 via Android 就该把 Linux 内核放到 Visual Studio 编译 |
25 fighte97 2021-03-04 16:05:50 +08:00 C#可以多用用 能搞懂很多 C/C++的坑 |
26 jim9606 2021-03-04 17:34:38 +08:00 局部变量没有初始化的话初值不一定为 0,指针好像也是这样的,所以 char*还是习惯初始化为 NULL 或者 malloc 。 如果需求定长 64 位的 int 类型,应该用 stdint.h 标头里的 uint64_t,在 printf/scanf 中用 inttypes.h 标头里的宏 PRIu64/SCNu64,如果是地址应该用 intptr_t/PRIiPTR/SCNiPTR |
27 Rrobinvip 2021-03-04 21:27:28 +08:00 via iPhone 注意到你最后更正的地方还有一个致命问题,可能是因为要转换的 str 太短了没体现出来 你用 `int size = sizeof(Val)`, 然后给 str malloc 这么多空间。事实上无论你的 val 指向的 str 到底有多大,这个 size 永远都是 8,因为你得到的是一个 pointer 的大小,而不是实际 string 的长度。 我感觉你的想法是,看一下 val 这个 str 有多长,然后给 str malloc 这么多空间吧? 所以你应该用 `size_t size=strlen(Val)+1` ,然后再 malloc 。 |