Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/71.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
这是(char*)&;x铸件';谁的行为很明确?_C_String_Casting_Character - Fatal编程技术网

这是(char*)&;x铸件';谁的行为很明确?

这是(char*)&;x铸件';谁的行为很明确?,c,string,casting,character,C,String,Casting,Character,在编写一些C代码时,我遇到了一个小问题,我必须将一个字符转换为“字符串”(一些内存块,其开头由char*指针给出) 其思想是,如果设置了某个sourcestr指针(而不是NULL),则应将其用作“最终字符串”,否则应将给定的charcode转换为另一个数组的第一个字符,并改用它 对于这个问题,我们假设变量的类型不能事先更改。换句话说,我不能将我的charcode存储为const char*而不是int 因为我很懒,我想:“嘿,我能不能用字符的地址把指针当作字符串来处理?”。下面是我写的一小段话(

在编写一些C代码时,我遇到了一个小问题,我必须将一个字符转换为“字符串”(一些内存块,其开头由
char*
指针给出)

其思想是,如果设置了某个
sourcestr
指针(而不是
NULL
),则应将其用作“最终字符串”,否则应将给定的
charcode
转换为另一个数组的第一个字符,并改用它

对于这个问题,我们假设变量的类型不能事先更改。换句话说,我不能将我的
charcode
存储为
const char*
而不是
int

因为我很懒,我想:“嘿,我能不能用字符的地址把指针当作字符串来处理?”。下面是我写的一小段话(现在还不要把我的头撞到墙上!)

现在我当然试过了,正如我所预料的,它确实有效。即使有几个警告标志,编译器仍然很高兴。然而,我有一种奇怪的感觉,这实际上是一种未定义的行为,我不应该这样做

我之所以这样认为,是因为
char*
数组需要以null结尾,才能正确地打印为字符串(我希望我的数组也是如此!)。但是,我不能确定
&charcode+1
处的值是否为零,因此可能会导致缓冲区溢出

它工作正常有什么实际原因吗,还是我在尝试时幸运地在正确的位置得到了零?

(注意,我没有寻找其他方法来实现转换。我可以简单地使用
chartmp[2]={0}
变量,并将我的字符放在索引0处。我也可以使用类似于
sprintf
snprintf
的东西,只要我对缓冲区溢出足够小心。有很多方法可以做到这一点,我只对这个特定强制转换操作的行为感兴趣。)


编辑:我见过一些人称之为黑客的人,让我们明确一点:我完全同意你的看法。我不是一个受虐狂,不会在发布的代码中真正做到这一点。这只是我越来越好奇;)

您的代码定义良好,因为您始终可以强制转换为
char*
。但有些问题:

  • 请注意,
    “BAR”
    是一个
    常量字符*
    文本-因此不要试图修改内容。这是没有定义的

  • 不要试图将
    (char*)&charcode
    用作C标准库中任何字符串函数的参数。它将以空结尾。所以从这个意义上讲,你不能把它当作一个字符串

  • (char*)&charcode
    上的指针算法将在标量
    charcode
    之前(包括标量之后)有效。但是不要尝试取消引用
    charcode
    本身之外的任何指针。表达式
    (char*)&charcode+n
    有效的
    n
    范围取决于
    sizeof(int)


  • 强制转换和赋值,
    char*finalstr=(char*)&charcode已定义

    使用printf作为字符串打印
    finalstr
    %s
    ,如果它指向
    charcode
    ,则是未定义的行为

    不要诉诸黑客手段并在类型
    int
    中隐藏字符串,而是使用选择的转换函数将整数中存储的值转换为字符串。一个可能的例子是:

    char str[32] = { 0 };
    snprintf( str , 32 , "%d" , charcode );
    char* finalstr = sourcestr ? sourcestr : str;
    

    或者使用您喜欢的任何其他(定义的!)转换。

    这是绝对未定义的行为,原因如下:

  • 不太可能,但要在严格引用标准时考虑:在编译代码
  • 的机器/系统上,您不能假定IsIf of int。
  • 如上所述,您不能假设代码集。例如,EBCDIC机器/系统上发生了什么
  • 很容易说你的机器有一个小小的endian处理器在big-endian机器上,由于big-endian内存布局,代码失败
  • 因为在许多系统上,
    char
    是一个有符号整数,就像
    int
    一样,当您的char是负值时(即在具有8位
    char
    的机器上,
    127
    ),如果您按照下面的代码分配值,可能会由于符号扩展而失败
  • 代码:


    关于第3点:您的字符串将在一个小的endian机器中以NULL结尾,该机器具有
    sizeof(int)>sizeof(char)
    char
    的正值,因为int的MSB将是0,并且这种endianess的内存布局是LSB-MSB(LSB优先).

    就像其他人所说的那样,它正好起作用,因为您机器上的int的内部表示形式是little endian,并且您的字符小于int。此外,您的字符的ascii值低于128,或者您有无符号字符(否则将有符号扩展)。这意味着字符的值位于int表示形式的低位字节中,int的其余部分将全部为零(假设int的任何正常表示形式)。你并不“幸运”,你有一台相当普通的机器

    将char指针指定给任何需要字符串的函数也是完全未定义的行为。您现在可能会侥幸逃脱,但编译器可以自由地将其优化为完全不同的内容

    例如,如果您在该赋值之后执行
    printf
    ,编译器可以自由地假设您总是将有效字符串传递给
    printf
    ,这意味着检查
    sourcestr
    是否为NULL是不必要的,因为如果
    sourcestr
    为NULL
    printf
    将使用非字符串的内容调用,编译器可以自由地假设未定义的行为永远不会发生。也就是说
    char str[32] = { 0 };
    snprintf( str , 32 , "%d" , charcode );
    char* finalstr = sourcestr ? sourcestr : str;
    
    char ch = FOO;
    int charcode = ch;