Использование разницы указателей с printf(%.*s)

Проблема, с которой я столкнулся, связана с типом данных 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);
            }
        }
    }
}
  • #P3# <блочная цитата> #P4#
  • #P5# <блочная цитата> #P6#

Теперь это демонстрационный код, и максимальный размер, который может содержать o, здесь равен 500, однако в моем реальном коде он может быть 10,000 или даже 100,000 (все еще очень в пределах размера 32-битного int, не Это?)

Так что же решит эту наилучшую проблему с наименьшими изменениями?

Скомпилировано на Clang (может быть очень похоже на GCC) с -Wall -Wextra -pedantic.


person user13863346    schedule 12.09.2020    source источник
comment
intptr_t o; = p-in; — это синтаксическая ошибка, так насколько это потенциально далеко от реального кода?   -  person Ry-♦    schedule 12.09.2020
comment
@Ry- Это фрагмент реального кода с небольшой ошибкой Ctrl-C и Ctrl-V В реальном коде переменные объявляются над этими операторами, так что это не проблема! (здесь поправил, спасибо)   -  person user13863346    schedule 12.09.2020
comment
Не могли бы вы просто сделать *p = 0; и просто использовать %s?   -  person Retired Ninja    schedule 12.09.2020
comment
@RetiredNinja Я не понимаю, что ты имеешь в виду   -  person user13863346    schedule 12.09.2020
comment
Завершите строку разделителем, а затем просто напечатайте ее. Вы даже можете использовать fputs, если хотите.   -  person Retired Ninja    schedule 12.09.2020
comment
@RetiredNinja Я использую это здесь, и это довольно блестяще. Однако в другом месте я не могу прервать или перезаписать свою строку (где я заменяю фразы в строке), что является типом места, где это не может хоть будь хорош. Однако, что касается рассматриваемого кода, это жизнеспособное решение.   -  person user13863346    schedule 12.09.2020


Ответы (2)


Разница двух указателей - это тип ptrdiff_t. ... представляет собой целочисленный тип со знаком результата вычитания двух указателей;

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

Учитывая, что они оба указывают на char in[501], разница также соответствует int.
Простое приведение. .* ожидает совпадения int, а не intptr_t или ptrdiff_t.

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

Или все сразу:

fprintf(write,"%.*s", (int) (p - in), in);
person chux - Reinstate Monica    schedule 12.09.2020
comment
Что стандарт говорит о размере int ? В реальном коде используется строка размером 10,000, так что она должна переносимо помещаться в int, верно? - person user13863346; 12.09.2020
comment
@user13863346 user13863346 Согласно спецификации C, int имеет по крайней мере диапазон [-32767...32767] и обычно сегодня имеет размер 4 байта с диапазоном +/- (2^31 - 1). Код с использованием printf() или fwrite(), как предложено в другом месте. Лучше всего использовать то, что упрощает понимание вашего кода. - person chux - Reinstate Monica; 12.09.2020

p-in больше похоже на ptrdiff_t или size_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);
}

Затем добавьте проверку ошибок.

person Community    schedule 12.09.2020
comment
@user13863346: Я бы сказал, что fprintf с %.*s в целом здесь не очень хорошая идея, да, но особенно не тогда, когда это вся строка формата. Тогда нет причин не использовать fwrite. - person Ry-♦; 12.09.2020
comment
разница в ptrdiff_t, а не в size_t, который является беззнаковым типом!! и 2 даже не обязательно должны быть одинаковой ширины - person Antti Haapala; 12.09.2020
comment
@AnttiHaapala: В этом случае известно, что результатом является размер. - person Ry-♦; 12.09.2020