我应该使用更通用的变量 alias/type 还是使用我将使用的函数采用的变量类型?

Should I use a more universal variable alias/type or use the variable type's that the functions i will use take?

问题介绍

所以几个月前,当我真的在努力提高 C 语言水平时,我决定也许是时候放弃通常的 var 类型,char、short、int、long,转而使用 stdint.h 那些是 uint8_t,等等...最初的问题是在某些机器上声明 long 的字节大小长度与其他机器不同,但很快我开始发现它对我来说变得势利了“将我与其他 IT 学生区分开来。

我现在正在做一个项目,和往常一样,我开始使用上面提到的变量别名,因为它们对我来说很容易阅读、写作,而且我不必想知道我的电脑会分配什么样的存储空间选择使用(我知道大小不会随意改变并且它取决于计算机 运行 它,但不明显和明确导致我只是痴迷于它)。

像往常一样,我的调试器不时开始抱怨,尤其是由于指针转换如此

Passing 'int8_t *' (aka 'signed char *') to parameter of type 'char *' converts between pointers to integer types where one is of the unique plain 'char' type and the other is notclang(-Wpointer-sign)

问题

虽然我通常只是明确地转换它们,但我只是想知道我是否因为我的偏好而使代码变得更糟,以及什么是好的做法:使用更通用的(对项目而言)变量别名,或者只是根据别名的使用方式使用别名(这意味着在一个文件上使用 2-3 个不同的别名,并且可能在整个项目范围内使用 10 个以上)?

例子

        png_voidp per_chunck_ptr; 
        size_t readnum; 
        FILE *fp;
        if ((fp = fopen(file, "rb")) == NULL){
            fp = NULL;
            //ERROR()
            //ABORT(GENERAL_OPENING_READ_FILE_ERROR, " ERR01 ");
        }
        int8_t *pop;
        pop=malloc(GENERAL_PNG_SIG_SIZE * sizeof(int8_t));
        readnum=fread(pop,sizeof(int8_t),GENERAL_PNG_SIG_SIZE,fp);
        if(readnum!=GENERAL_PNG_SIG_SIZE){
            fclose(fp);
            //ERR 5
            fp = NULL;
            fprintf(stderr, GENERAL_READ_FILE_ERROR, "ERR02");
            exit(5);
        }
        if(png_sig_cmp((png_const_bytep)pop, 0, GENERAL_PNG_SIG_SIZE)!= 0){
            fclose(fp);
            fp = NULL;
            fprintf(stderr, "File is not recognized as png file\n");
            //err 6
            exit(6);
        }
        free(pop);

错误检查很糟糕,我使用了 6-7 种不同的方式来打印错误,除了我学习新功能或只是分心并使用了某个功能并忘记了它之外没有其他原因但是尽管答案可以扩展到它,但让我们现在只关注变量 pop

当时我非常确定指针“pop”将来会用作通常更喜欢 png_bytep 或在本例中为 png_const_bytep 的函数的参数,而且我该库有自己的内存分配函数,尽管从我所见它的方式与使用 malloc 没有太大区别,(尽管我没有阅读具体实现的手册并且只知道一些通用的理论概念指定(如果你还没有弄清楚,它的 PNG)。

现在让我们关注 size_t readnum,这部分违背了我之前所说的,因为我使用了另一个别名,而我本可以说 uint64_t,如果我没有错的话size_t can store the maximum size of a theoretically possible object of any type (including array).(尽管有更大“单词”的类型,比如 long double,我读到的是 10 个字节长,或者 __uint128_t 其中 16 个字节,这些 cpu 并且他们需要对软件进行优化才能存储和操作它们,如果我错了请再次在这里纠正我)所以我不应该在这里使用 uint8_t 因为我知道如果有一天 cpu 制造商决定增加寄存器存储、ALU 和内存地址的位大小(我听说我的教授甚至说现代英特尔有时有大约 80 位)到 128 位 size_t 会移动如果它溢出,我的功能可能会失败。这导致我无法使用 uint64_t

结论

所以我应该停止使用我对精确变量大小的偏好,而是使用函数使用的变量别名,或者使用精确大小别名真的更好,因为它们允许更精确地定义某些行为

作为一般规则,当您需要精确控制特定变量的大小、使用任何类型的位操作或处理原始数据时,请使用精确宽度类型。在与指定这些类型的 API 交互时,您将使用基本类型,即如果函数需要 long,则将其传递给 long 而不是 uint64_t

关于您收到的具体警告,那是因为 char 类型可能是有符号或无符号的,具体取决于实现。因此,如果您要将 int8_t * 传递给期望 char * 的函数,并且该系统恰好将 char 定义为无符号类型,那么您就有了不匹配。

但这没什么大不了的,因为允许通过指向其类型的有符号或无符号版本的指针访问整数对象。

首先,您为什么要尝试将 int8_t * 转换为 char *(又名 uint8_t *)?该警告是为了您代码的安全。这不是因为您使用了别名,而是因为您将有符号整数类型隐式转换为无符号整数类型。

实际上,您应该使用 API 期望的任何内容。而且,如果您不使用任何其他库或类似的东西,请使用最适合您的东西。如果您想具体说明大小,请使用 stdint.h 值,如果您想模糊说明大小(例如,您想要第二大类型),请使用普通的 C 关键字。请注意,“第二大”类型可能与最大或第三大类型相同。