LINUX.ORG.RU

«Ненормальное» сравнение переменной shn с единицей.


0

1

Вот код:

#include <unistd.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/stat.h> 
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#define _GNU_SOURCE
#include <getopt.h>
void itoa(register unsigned long n, register char s[]);
void dchk(int f);
int ferr();
int usage();
int main(int argc, char** argv){
    register int ch;
    int longIndex;
    register short sht, shn, shcc, num;
    static const struct option longOpts[] = {
    { "show-nonprinting", no_argument, NULL, 'v' },
    { "show-tabs", no_argument, NULL, 'T' },
    { "show-ends", no_argument, NULL, 'E' },
    { "show-all", no_argument, NULL, 'A' },
    { "number", no_argument, NULL, 'n' },
    { "version", no_argument, NULL, 0 },
    { NULL, no_argument, NULL, 0 }
    };
    while((ch=getopt_long(argc, argv, "ETAethun",longOpts,&longIndex))!= -1){
        switch (ch) {
                case 'n':
                    num = 1;
                    break;
                case 'E':
                    shn = 1;
                    break;
                case 'T':
                    sht=1;
                    break;
                case 'A':{
                    shn=1;
                    sht=1;
                    shcc=1;
                    break;
                    }
                case 'v':
                    shcc=1;
                    break;
                case 'e':{
                    shcc=1;
                    shn=1;
                    break;
                    }
                case 't':{
                    shcc=1;
                    sht=1;
                    break;
                    }
                case '?':
                case 'h':
                    usage();
                case 'u':
                    break;
                case 0:if(strcmp( "version",longOpts[longIndex].name)==0){
                    write(1,"sysccat version 0.1\n",20);
                    _exit(0);
                    }
                    else usage();
                }
        }
    argv+=optind;
    argc-=optind;
    if(argc==0)usage();
    if(!sht&&!shn&&!shcc&&!num)for(int x=0;x<argc;++x){
        int fd=open(argv[x],O_RDONLY);
        if(fd<0)ferr();
        dchk(fd);
        char a;
        while(read(fd,&a,1)>0)write(0,&a,1);
        close(fd);
    }
        else for(int x=0;x<argc;++x){
            int fd=open(argv[x],O_RDONLY);
            if(fd<0)ferr();
            dchk(fd);
            if(num)write(0,"1: ",3);
            register int i=1;
            char a;
            while(read(fd,&a,1)>0){
                if(num&&a=='\n'){
                                if(read(fd,&a,1)==0){
                                                    if(shn)write(0,"$",1);
                                                    write(0,&a,1);
                                                    }
                                else{
                                    if(shn)write(0,"$",1);
                                    write(0,"\n",1);
                                    char b[11];
                                    ++i;
                                    itoa(i,b);
                                    write(0,&b,strlen(b));
                                    write(0,": ",2);
                                    lseek(fd, -1, SEEK_CUR);
                                    }
                }
                else if(sht&&a=='\t')write(1,"^I",2);
                    else if((shn==1)&&a=='\n')write(1,"$\n",2);
                        else if(shcc&&iscntrl(a)&&a!='\n'&&a!='\t'){
                                                                    char c=a+64;
                                                                    write(1,"^",1);
                                                                    write(1,&c,1);
                                                                    }
                            else write(1,&a,1);
        }
        close(fd);
    }
    _exit(0);
}
int usage(){
    write(1,"Usage: sysccat [OPTIONS]... [FILE]...\n"
    "-h or --help Displays this info and exit.\n"
    "-n or --number Numbers the output strings.\n"
    "--version Displays version and exit.\n"
    "-v or --show-nonprinting Displays non-printing(control) characters, except for tabulation and carriage return/end-of-line symbols.\n"
    "-A, -vET or --show-all Displays all control characters.\n"
    "-t or -vT Displays all control characters, except for carriage return/end-of-line symbol.\n"
    "-u Ignored; for POSIX compatibility.\n"
    "-e or -vE Displays all control characters, except for tabulation symbol.\n",547);
    _exit(0);
    }
void itoa(register unsigned long n, register char s[]){
     register short i,j;
     register char c;
     i=0;
     do{
         s[i++] = n % 10 + '0';
     }while((n/=10)>0);
     s[i]='\0';
     for(i=0,j=strlen(s)-1;i<j;i++,j--){
         c = s[i];
         s[i] = s[j];
         s[j] = c;
     }
 }
int ferr(){
    switch(errno){
        case ENOENT:
            write(0,"No such file or directory.\n",27);
            break; 
        case EACCES:
            write(0,"Access denied.\n",15);
            break;
        default:
            write(0,"Unknown error\n",14);
            break;
    }
    _exit(1);
}
void dchk(int f){
    struct stat fs;
    fstat(f,&fs);
    if(S_ISDIR(fs.st_mode)){
        write(0,"It's a directory.\n",18);
        close(f);
        _exit(1);
        }
}
Так вот, если в строчке else if((shn==1)&&a=='\n')write(1,«$\n»,2); заменить if((shn==1)&&a=='\n') на if(shn&&a=='\n') то прога постоянно считает это условие истинным, даже если проге не переданы опции -E , -A или -e, присваивающие этой переменной значение 1, при этом в других местах такая конструкция работает нормально. С чем это связано? Заранее спасибо тем, кто поможет.

★★

> write(0,…);

ну и как оно, в stdin писать? на клавиатуре текст появляется?

arsi ★★★★★ ()

if (shn) сработает при любых значениях shn != 0. Эта переменная у тебя не инициализируется, так что после запуска программы там может быть любой мусор.

Deleted ()
Ответ на: комментарий от Deleted

Т.е. просто нициализировать все переменные? Насколько я понимаю, если бы это была глобальная переменная, то она автоматически бы инициализировалась нулём, но так как она register, то делать её глобальной нельзя, нужно просто вручную роинициализировать?

Dorif ★★ ()
Ответ на: комментарий от Dorif

> Насколько я понимаю, если бы это была глобальная переменная, то она автоматически бы инициализировалась нулём

С чего бы? Там что угодно может быть

different_thing ()
Ответ на: комментарий от Dorif

> 0- дескриптор stdout.

а мужики-то и не знают ;)

man stdin

On program startup, the integer file descriptors associated with the streams stdin, stdout, and stderr are 0, 1, and 2, respectively.

arsi ★★★★★ ()
Ответ на: комментарий от arsi

Ой, действительно.. Вот, что значит ошибиться в одном месте, а потом почти весь код так подправить...

*Из колодца лезут руки?

Не волнуйтесь!

Это- ГЛЮКИ!

Dorif ★★ ()
Ответ на: комментарий от different_thing

Ну, когда переменная была объявлена перед main() всё работало прекрасно при всех условиях. так что...

Dorif ★★ ()
Ответ на: комментарий от Dorif

там же

… The preprocessor symbols STDIN_FILENO, STDOUT_FILENO, and STDERR_FILENO are defined with these values in <unistd.h>.

более читабельно + меньше шансов допустить глупые ошибки.

arsi ★★★★★ ()
Ответ на: комментарий от Dorif

... повезло, наверное)

Всё таки не надо полагаться на авось. Это как

i = 5; i = ++i + ++i;

Авось проканает, но всё же.

different_thing ()
Ответ на: комментарий от arsi

А вот это не знал. И если так делать, то теоретически прога будет работать даже в ОС, в которой эти значения изменены(типа если писал кто- то вроде печально известного Дениса Попова.).)

Dorif ★★ ()
Ответ на: комментарий от Dorif

можно ещё «int fd = fileno(stdout);» использовать, оно вроде даже в виндах есть.

arsi ★★★★★ ()
Ответ на: комментарий от arsi

Не, эт уже слишком.))) Ещё одну операцию выполнять, удлинять за счёт этого исполняемый файл... А предыдущий вариант- прекрасен тем, что препроцессор сам при компиляции подставит необходимые значения и исполняемый файл по размеру получится такоим же, как при явном указании файлового дескриптора, но исходники будут более читабельными. А с этим вариантом- дополнительная вычислительная нагрузка(маленькая, но всё же...)))).

Dorif ★★ ()
Ответ на: комментарий от Deleted

А если битовое поле юзать, там тоже что угодно может быть? Или как?

Dorif ★★ ()
Ответ на: комментарий от Dorif

Лучше инициализировать все переменные. В локальных мусор будет почти гарантированно, в глобальных зависит от платформы, компилятора или даже его опций.

Кстати, register использовать вроде как не совсем нужно. Компилятор сам всё сделает так, чтобы быстрее работало.

Yareg ★★★ ()
Ответ на: комментарий от Yareg

> в глобальных зависит от платформы, компилятора или даже его опций.

да неужели?

ISO/IEC 9899:1999

If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. If an object that has static storage duration is not initialized explicitly, then:

  • if it has pointer type, it is initialized to a null pointer;
  • if it has arithmetic type, it is initialized to (positive or unsigned) zero;
  • if it is an aggregate, every member is initialized (recursively) according to these rules;
  • if it is a union, the first named member is initialized (recursively) according to these rules.
arsi ★★★★★ ()
Ответ на: комментарий от Yareg

суть такая же, но в стандарте это очень многословно описано и размазано по нескольким главам:

ISO/IEC 14882:2003

3 Basic concepts

3.6 Start and termination

3.6.2 Initialization of non-local objects

Objects with static storage duration (3.7.1) shall be zero-initialized (8.5) before any other initialization takes place. Zero-initialization and initialization with a constant expression are collectively called static initialization; all other initialization is dynamic initialization. Objects of POD types (3.9) with static storage duration initialized with constant expressions (5.19) shall be initialized before any dynamic initialization takes place. Objects with static storage duration defined in namespace scope in the same translation unit and dynamically initialized shall be initialized in the order in which their definition appears in the translation unit. [Note: 8.5.1 describes the order in which aggregate members are initialized. The initialization of local static objects is described in 6.7. ]

* * *

8 Declarators

8.5 Initializers

To zero-initialize an object of type T means:

  • if T is a scalar type (3.9), the object is set to the value of 0 (zero) converted to T;
  • if T is a non-union class type, each nonstatic data member and each base-class subobject is zero-initialized;
  • if T is a union type, the object’s first named data member is zero-initialized;
  • if T is an array type, each element is zero-initialized;
  • if T is a reference type, no initialization is performed.
arsi ★★★★★ ()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.