I came across this post discussing how to print file permissions from the stat
library, but I'm confused on how the definition of the struct works.
When I've defined structs, I've always defined them like struct struct_type *name
. But in the example the struct is defined like struct struct_type name
(without being a pointer). From what I can tell, there should be two different ways to access the information depending on how you define the struct.
Option One Notation
struct stat fileStat; //definition of struct
stat("<filename>", &fileStat); //execute the stat function
fileStat.member_name; //access a member of a struct
Option Two Notation
struct stat *fileStat; //definition of struct
stat("<filename>", fileStat); //execute the stat function
fileStat->member_name; //access a member of a struct
BUT when I switch things from option one notation in the provided example to option two I get VERY different results. What is different about these two options? Isn't it effectively doing the same thing?
Example Code
Option One Notation Program
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(int argc, char **argv)
{
struct stat fileStat;
stat("main", &fileStat);
printf("Information for %s\n", argv[1]);
printf("---------------------------\n");
printf("File Size: \t\t%lld bytes\n", fileStat.st_size);
printf("Number of Links: \t%d\n", fileStat.st_nlink);
printf("File inode: \t\t%llu\n", fileStat.st_ino);
printf("File Permissions: \t");
printf( (S_ISDIR(fileStat.st_mode)) ? "d" : "-");
printf( (fileStat.st_mode & S_IRUSR) ? "r" : "-");
printf( (fileStat.st_mode & S_IWUSR) ? "w" : "-");
printf( (fileStat.st_mode & S_IXUSR) ? "x" : "-");
printf( (fileStat.st_mode & S_IRGRP) ? "r" : "-");
printf( (fileStat.st_mode & S_IWGRP) ? "w" : "-");
printf( (fileStat.st_mode & S_IXGRP) ? "x" : "-");
printf( (fileStat.st_mode & S_IROTH) ? "r" : "-");
printf( (fileStat.st_mode & S_IWOTH) ? "w" : "-");
printf( (fileStat.st_mode & S_IXOTH) ? "x" : "-");
printf("\n\n");
printf("The file %s a symbolic link\n", (S_ISLNK(fileStat.st_mode)) ? "is" : "is not");
return 0;
}
Option One Notation Output
Information for (null)
---------------------------
File Size: 49960 bytes
Number of Links: 1
File inode: 58527531
File Permissions: -rwxr-xr-x
The file is not a symbolic link
Option Two Notation Program
#include <unistd.h>
#include <stdio.h>
#include <sys/stat.h>
#include <sys/types.h>
int main(int argc, char **argv)
{
struct stat *fileStat;
stat("main", fileStat);
printf("Information for %s\n", argv[1]);
printf("---------------------------\n");
printf("File Size: \t\t%lld bytes\n", fileStat->st_size);
printf("Number of Links: \t%d\n", fileStat->st_nlink);
printf("File inode: \t\t%llu\n", fileStat->st_ino);
printf("File Permissions: \t");
printf( (S_ISDIR(fileStat->st_mode)) ? "d" : "-");
printf( (fileStat->st_mode & S_IRUSR) ? "r" : "-");
printf( (fileStat->st_mode & S_IWUSR) ? "w" : "-");
printf( (fileStat->st_mode & S_IXUSR) ? "x" : "-");
printf( (fileStat->st_mode & S_IRGRP) ? "r" : "-");
printf( (fileStat->st_mode & S_IWGRP) ? "w" : "-");
printf( (fileStat->st_mode & S_IXGRP) ? "x" : "-");
printf( (fileStat->st_mode & S_IROTH) ? "r" : "-");
printf( (fileStat->st_mode & S_IWOTH) ? "w" : "-");
printf( (fileStat->st_mode & S_IXOTH) ? "x" : "-");
printf("\n\n");
printf("The file %s a symbolic link\n", (S_ISLNK(fileStat->st_mode)) ? "is" : "is not");
return 0;
}
Option Two Notation Output
Information for (null)
---------------------------
File Size: 5193343115435036343 bytes
Number of Links: 12487
File inode: 930377443599221576
File Permissions: -r-x--x---
The file is not a symbolic link
CodePudding user response:
This is not an alternate notation
struct stat *fileStat; //definition of struct
stat("<filename>", fileStat); //execute the stat function
fileStat->member_name; //access a member of a struct
it is invalid code. You have created a pointer that doesnt point anywhere. It needs to point at an instance of a stat. Like this
struct stat other_stat;
struct stat *fileStat; //definition of struct
fileStat = &other_stat; // make it point at the instance we just made
stat("<filename>", fileStat); //execute the stat function
fileStat->member_name; //access a member of a struct
or create one on the heap
struct stat *fileStat = (struct stat*)malloc(sizeof(struct stat));
stat("<filename>", fileStat); //execute the stat function
fileStat->member_name; //access a member of a struct
In your 'second notation' example, once you did this
stat("filename", fileStat)
all bets were off. Stat has written data to an unspecified location. This results in 'Undefined Behavior'. You could be lucky and write to a location that cant be written to. In this case you program would abort immediately. Why is that lucky? well you would know something was wrong. The worst kind of behavior is that you end up writing to a location that's writable and is not being used for anything else at the moment. Your program will work and you will ship it, then a customer tries it with a file with a longer file name or after an OS upgrade or on a machine with a different amount of memory and 'boom' it gives wierd answers or dies. This is why langauges like Java, c#, go etc exist. So as not to get into this mess.