【问题标题】:Using difference of pointers with printf("%.*s")使用 printf("%.*s") 的指针差异
【发布时间】:2020-12-30 13:17:31
【问题描述】:

我面临的问题与 intptr_t 数据类型以及 fprintf() 采用 %.*s 格式的参数的方式有关。 %.*s 格式期望字段精度为 int 类型,这本身可能不是不合理的。

但在这种情况下不是:

#include <stdio.h>
#include <stdint.h>
int main() {
    char fname[] = "Some_File.txt";
    FILE *write = fopen(fname,"w");
    
    if(write!=NULL){

        printf("\n\tType below :\n\n");
        char in[501]=""; char *p;

        while(1){
            fgets(in,MAX_LN,stdin);

    /*** Region with compiler warnings begins ***/
            if((p=strstr(in,"/end/"))!=0){
                intptr_t o = p-in;
                fprintf(write,"%.*s",o,in);
    /*** Region with compiler warnings ends ***/
                fclose(write);
                break;
            }
            else{
                fputs(in,write);
            }
        }
    }
}
  • 如果我编译这个,它不能很好地与%.*s 配合使用,编译器指出了这一点:

    警告:字段精度的类型应为“int”,但参数的类型为“intptr_t”(又名“long”)[-Wformat]

  • 如果我把它设为int o;,它与%.*s 配合得很好,但当然不理想,编译器也这么说:

    警告:隐式转换会丢失整数精度:'long' 到 'int' [-Wshorten-64-to-32]

现在,这是演示代码,这里o 可以容纳的最大大小是500,但是,在我的实际代码中,它可以是10,000 甚至100,000(仍然在32 位 int 的大小,不是吗?)

那么用最少个改动解决这个最好的方法是什么?

使用 -Wall -Wextra -pedantic 在 Clang 上编译(在 GCC 上可能非常相似)。

【问题讨论】:

  • intptr_t o; = p-in; 是一个语法错误,那么这可能与真实代码相差多远?
  • @Ry- 这是来自真实代码的 sn-p,带有一个小的 Ctrl-C & Ctrl-V 错误真实代码在这些语句上方声明了变量,所以它那里不是问题! (我在这里更正了,谢谢)
  • 你不能只使用*p = 0; 并使用%s吗?
  • @RetiredNinja 我不确定你的意思
  • @RetiredNinja 我在这里使用它,它非常棒。但是,在另一个地方,我无法终止或覆盖我的字符串(我正在替换一行中的短语),即虽然这可能不是很好的地方类型。但是,就有问题的代码而言,这是一个可行的解决方案

标签: c pointers integer printf format-specifiers


【解决方案1】:

两个指针的区别是类型ptrdiff_t。 "...是两个指针相减结果的有符号整数类型;"

// intptr_t o = p-in;
ptrdiff_t o = p - in;

鉴于这两个点都在char in[501] 中,差异也适合int
简单地施放。 .* 期望匹配 int,而不是 intptr_tptrdiff_t

// fprintf(write,"%.*s",o,in);
fprintf(write,"%.*s", (int) o, in);

或一次性:

fprintf(write,"%.*s", (int) (p - in), in);

【讨论】:

  • 标准对int 的大小有何规定?真正的代码使用大小为 10,000 的字符串,所以这应该可以移植到 int 中,对吧?
  • @user13863346 根据 C 规范,int 至少 的范围为 [-32767...32767],现在通常是 4 字节,范围为 + /- (2^31 - 1)。使用printf()fwrite() 的代码,如其他地方所建议的那样。最好使用使您的代码最容易理解的任何东西。
【解决方案2】:

p-in 更像是 ptrdiff_tsize_t。无论如何,在这种情况下,我会使用fwrite

if ((p = strstr(in, "/end/")) != NULL) {
    size_t len = p - in;
    fwrite(in, sizeof(char), len, write);
    fclose(write);
    break;
} else {
    fputs(in, write);
}

然后添加错误检查。

【讨论】:

  • @user13863346:我会说fprintf%.*s 通常在这里不是一个好主意,是的,但尤其是当它是整个格式字符串时。那么没有理由不使用fwrite
  • 区别是ptrdiff_t,而不是size_t,它是一个无符号类型!!并且 2 甚至不需要具有相同的宽度
  • @AnttiHaapala:在这种情况下,我们知道结果是一个大小。
猜你喜欢
  • 1970-01-01
  • 2022-08-06
  • 1970-01-01
  • 1970-01-01
  • 2018-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多