我可以使用 int8_t 代替 char 吗?

Posted

技术标签:

【中文标题】我可以使用 int8_t 代替 char 吗?【英文标题】:Can I use int8_t instead of char? 【发布时间】:2022-01-23 00:25:30 【问题描述】:

我做了一个如下所示的短代码。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>
 
int32_t main(int32_t argc, int8_t *argv[])

   int32_t i;
 
   if (argc < 1)
   
      printf("Error\n");
   
 
   for (i = 0 ; i < argc ; i++)
   
      printf("argv[%d] = %s\n", i, argv[i]);
   
 
   return 0;

如下所示编译,然后我看到如下警告。

$ gcc -W -Wall main.c
main.c:6:9: warning: second argument of ‘main’ should be ‘char **’ [-Wmain]
 int32_t main(int32_t argc, int8_t *argv[])

使用 int8_t 的最佳做法是什么?

【问题讨论】:

charsigned charint8_t 可能是 typedef 的)是不同的类型,即使 char 已签名。见***.com/questions/2054939/… 【参考方案1】:

你的方法有很多缺点:

main() 的原型与任何标准原型都不兼容,即使 int 具有 32 位并且如果 char 已签名,因为 charsigned char 是不同但兼容的类型,但 @987654326 @ 和 signed char * 是不兼容的类型。

如果intint32_t不一样,则原型肯定与标准不兼容,行为未定义。

如果int 类型与int 不完全相同,printf("argv[%d] = %s\n", i, argv[i]); 将具有未定义的行为。您可以使用来自&lt;inttypes.h&gt; 的宏,但它们相当繁琐,并且代码可读性较差。

因此main 函数的原型应该是int main(int argc, char *argv[]),并且为了保持一致性,i 应该定义为与argc 相同的类型:int

生成的代码非常简单易读:

#include <stdio.h>
 
int main(int argc, char *argv[]) 
    int i;
 
    if (argc < 1) 
        printf("Error\n");
    
 
    for (i = 0; i < argc; i++) 
        printf("argv[%d] = %s\n", i, argv[i]);
    
 
    return 0;

我认为关于int8_tchar 的最佳实践是对main 和所有库函数使用未更改的标准原型。还建议使用char 用于文本的实际字符,而不是int8_tuint8_t 用于从二进制内容读取的有符号和无符号字节。字符串文字应被视为const 并通过const char * 进行操作。无论 char 类型的符号性如何,代码都应以定义的方式运行。这不仅仅是风格问题,这是提高代码可读性和坚固性、避免混淆和一些错误的明智习惯。

【讨论】:

【参考方案2】:

从根本上讲,我相信您是在问一个风格问题,这意味着您不太可能得到明确的答案。对风格的意见,嗯,意见。

有些人认为你应该使用 C 的“自然”类型——charshortintlong,以及它们的 unsigned 变体——大多数时候,你应该使用精确-size 类型,如int32_t,仅在您绝对需要时使用。

有些人认为“自然”类型所暗示的可变性是错误的源头,他们认为您应该始终使用精确大小的类型。

现在,说了这么多,具体的写法

int32_t main(int32_t argc, int8_t *argv[])

客观上是错误的,至少有三个原因:

    int 类型为16 位的平台上,这会错误地将main 的返回类型和argc 参数的类型声明为32 位类型。 在char 类型为无符号的平台上,这会错误地将argv 声明为有符号字符指针数组。这可能就是 gcc 为您抱怨的原因。 在更哲学的层面上,main 不是您可以选择其函数签名的函数。其他人声明main,其他人调用main,您的工作只是为main 提供定义。因此,您只需使用其他人指定的类型,即使您的规则是尽可能使用精确大小的类型。在这里,你不能。

底线:请为main 使用这两种(等效)形式之一,并带有参数:

int main(int argc, char *argv[])

int main(int argc, char **argv)

除非您正在编写“独立”代码,否则任何其他内容都是令人困惑、误导、不标准或错误的。 (定义一个不带参数的main 也是可以接受的。)

使用 int8_t 的最佳做法是什么?

我会说,当您真的需要一个很小的 ​​8 位有符号整数时,或者当您将内存作为有符号字节进行操作时。但我不会到处使用int8_t 而不是char,因为它会给你带来很多问题,而且不会给你带来任何好处。

【讨论】:

不是风格问题。更准确地说:int8_t 可能是 signed char 的别名,它与 char 的类型不同,即使 char 默认已签名。 该标准包含文本“...或等价物”,通过脚注“因此,int 可以替换为定义为 int 的 typedef 名称,或者可以编写 argv 的类型如 char ** argv 等等。” @chqrlie 问题的标题是一个风格问题。关于main的具体例子不是。 我同意这是风格问题。实际上,我喜欢使用精确尺寸类型而不是自然/传统类型的样式。但如前所述,我不能将它用于 main() 的 int8_t。即使 main() 只是我遇到问题的一种情况,这也让我感到困扰。因此,这意味着最佳实践是接受 main() 作为例外情况。好像。 @Cprogrammer:我认为最佳实践是对main 和所有库函数使用未更改的标准原型。还建议将char 用于文本的实际字符,而int8_tuint8_t 用于从二进制内容读取的有符号和无符号字节。字符串文字应被视为const 并通过const char * 进行操作。无论char 类型的签名如何,代码都应以定义的方式运行。这不仅仅是风格问题,这是提高可读性和坚固性、避免混淆和一些错误的明智习惯。【参考方案3】:

使用 int8_t 的最佳做法是什么?

当您需要一个非常小的有符号整数时。这与char 不同。 char 有三种风格:

signed char
unsigned char
char

如果您知道您想要一个签名的int8_t,请使用它。如果您正在处理标准字符串 API:s,例如 main,请使用 char

int8_t 甚至不需要存在。它是特定于实现的。有些平台不存在。

您使用 int32_t 代替 int 也是如此。它不一定存在,即使它存在,也不一定是 typedef 对应于 int - 如果您想保持便携性,请使用 int

【讨论】:

【参考方案4】:

您发布的是main() 的实现定义形式。仅在两种情况下允许:

要么与int main (int argc, char** argv) 100% 兼容,要么 这是一种实现定义的形式,编译器文档告诉您可以使用。

决定 main() 的可接受形式的是 C 标准和编译器,而不是程序员

值得注意的是,int8_t 可能与 char 兼容,也可能不兼容,因为 char 具有实现定义的签名。

【讨论】:

即使char默认签名,signed charchar也是不同的类型。 @chqrlie 是的,但如果它们具有相同的签名,则它们是兼容的类型。 “char、signed char 和 unsigned char 这三种类型统称为字符类型。实现应将 char 定义为与有符号字符或无符号字符具有相同的范围、表示和行为。” @Lundin 但是作为不同的类型,char**signed char** 不兼容。不管怎样,它们是不同的类型意味着main 函数定义不是一个有效的标准。 @Kevin main() 可以有各种签名int main(void)int main(int argc, char *argv[])、等效或一些其他实现定义的方式signed char **argv 不一定是无效的,但可能是。 @chux-ReinstateMonica 够公平的。我没有意识到允许实现为 main 提供其他有效签名:/* another implementation-defined signature */ (since C99)

以上是关于我可以使用 int8_t 代替 char 吗?的主要内容,如果未能解决你的问题,请参考以下文章

int32、int、int32_t、int8和int8_t的区别

从 int8_t 数组创建 std::string

C ++中是否存在实际的8位整数数据类型

列值采用 0 或 nul 代替 HIVE 中的 char 数据类型

我可以使用 AVAssetWriter 代替 AVExportSession 吗?

使用 LinearLayout 代替 FrameLayout 可以吗?